# source("utility.R")
source("R_functions.R")
source("R_data_prepocessing.R")

News headline

1st half 2020

AU_timeline %>% 
  filter(date <= ymd(20200515)) %>%
  arrange(date) %>% 
  # filter(nchar(event) < 230) %>% 
  # filter(region != "VIC") %>% 
  mutate(rowid = as.numeric(rownames(.))) %>% 
  mutate(date_gap = as.numeric(date-lag(date))) %>% 
  mutate(nchar = nchar(event), 
         nchar_scaled = (nchar-min(nchar))/(max(nchar)-min(nchar)), 
         # point_position = 700 * nchar_scaled * (-1)^rowid,
         point_position = c(100,100,280,320,550,20,100,550,720,150,
                            240,880,400,300)*(-1)^rowid
         ) %>% 
  mutate(facet_var = quarter(date, with_year = T)) %>% 
  
  ggplot(aes(x=date, y=0)) + 
  geom_line() + 
  geom_point(aes(col=region)) +
  geom_segment(aes(x=date, xend=date, col=region,
                   y=0, yend=point_position)) +
  geom_point(aes(y=point_position, col=region), shape=1) +
  geom_text(aes(y=-10, 
                label=paste0(day(date), " ", 
                             month(date, label=T))), 
            angle=30, 
            vjust=1, hjust=1) + 
  geom_label(aes(label=str_wrap(paste0(date, ": ", event), nchar/1.8), alpha=.7,
                 # directions="y", min.segment.length = Inf,
                 x=date, y=point_position, col=region, vjust="outward")) +
  scale_x_date(date_breaks = "1 month", 
               date_labels = "%b %Y") + 
  # facet_wrap(~facet_var, strip.position="top",
  #            ncol = 1, scales = "free_x") +
  # coord_flip() +
  ylim(-1200,1200) + 
  coord_cartesian(clip = "off") + 
  labs(subtitle = "AU/NSW Covid-19 timeline, 1st half 2020") +
  theme_void(base_size = 23) +
  theme(legend.position = "none", 
        # rect = element_rect(fill = "transparent"),
        plot.margin = unit(c(0, 2.3, 0, 2.3),"cm"),
        # plot.background = element_rect(fill = NULL)
        )

2nd half 2020

AU_timeline %>% 
  filter(date > ymd(20200515)) %>%
  arrange(date) %>% 
  # filter(nchar(event) < 230) %>% 
  # filter(region != "VIC") %>% 
  mutate(rowid = as.numeric(rownames(.))) %>% 
  mutate(date_gap = as.numeric(date-lag(date))) %>% 
  mutate(nchar = nchar(event), 
         nchar_scaled = (nchar-min(nchar))/(max(nchar)-min(nchar)), 
         # point_position = 700 * nchar_scaled * (-1)^rowid,
         point_position = c(50,100,280,420,550,720,100,550,720,150,
                            240,780,830,300)*(-1)^rowid
         ) %>% 
  mutate(facet_var = quarter(date, with_year = T)) %>% 
  
  ggplot(aes(x=date, y=0)) + 
  geom_line() + 
  geom_point(aes(col=region)) +
  geom_segment(aes(x=date, xend=date, col=region,
                   y=0, yend=point_position)) +
  geom_point(aes(y=point_position, col=region), shape=1) +
  geom_text(aes(y=-10, 
                label=paste0(day(date), " ", 
                             month(date, label=T))), 
            angle=30, 
            vjust=1, hjust=1) + 
  geom_label(aes(label=str_wrap(paste0(date, ": ", event), nchar/3), alpha=.7,
                 # directions="y", min.segment.length = Inf,
                 x=date, y=point_position, col=region, vjust="outward")) +
  scale_x_date(date_breaks = "1 month", 
               date_labels = "%b %Y") + 
  # facet_wrap(~facet_var, strip.position="top",
  #            ncol = 1, scales = "free_x") +
  # coord_flip() +
  ylim(-1200,1200) + 
  coord_cartesian(clip = "off") + 
  labs(subtitle = "AU/NSW Covid-19 timeline, 2nd half 2020") +
  theme_void(base_size = 23) +
  theme(legend.position = "none", 
        # rect = element_rect(fill = "transparent"),
        plot.margin = unit(c(0, 2.3, 0, 2.3),"cm"),
        # plot.background = element_rect(fill = NULL)
        )

Full

AU_timeline %>% 
  # filter(date >= ymd(20200220)) %>% 
  arrange(date) %>% 
  add_row(date = ymd(20200120), event="") %>%
  # add_row(date = ymd(20200220), event="") %>%
  add_row(date = ymd(20200331), event="") %>%
  add_row(date = ymd(20200401), event="") %>%
  add_row(date = ymd(20200630), event="") %>%
  add_row(date = ymd(20200701), event="") %>%
  add_row(date = ymd(20200930), event="") %>%
  add_row(date = ymd(20201001), event="") %>%
  # filter(nchar(event) < 230) %>% 
  # filter(region != "VIC") %>% 
  mutate(rowid = as.numeric(rownames(.))) %>% 
  mutate(date_gap = as.numeric(date-lag(date))) %>% 
  mutate(nchar = nchar(event), 
         nchar_scaled = (nchar-min(nchar))/(max(nchar)-min(nchar)), 
         point_position = 800 * nchar_scaled * (-1)^rowid,
         # point_position = c(100)*(-1)^rowid
         ) %>% 
  mutate(facet_var = quarter(date, with_year = T)) %>% 
  
  ggplot(aes(x=date, y=0)) + 
  geom_line() + 
  geom_point(aes(col=region)) +
  geom_segment(aes(x=date, xend=date, col=region,
                   y=0, yend=point_position)) +
  geom_point(aes(y=point_position, col=region), shape=1) +
  geom_text(aes(y=-10, 
                label=paste0(day(date), " ", 
                             month(date, label=T))), 
            angle=30, 
            vjust=1, hjust=1) + 
  geom_label(aes(label=str_wrap(paste0(date, ": ", event), nchar/2), alpha=.7,
                 # directions="y", min.segment.length = Inf,
                 x=date, y=point_position, col=region, vjust="outward")) +
  scale_x_date(date_breaks = "1 month", 
               date_labels = "%b %Y") + 
  facet_wrap(~facet_var, strip.position="top",
             ncol = 1, scales = "free_x") +
  # coord_flip() +
  ylim(-1200,1200) + 
  coord_cartesian(clip = "off") + 
  theme_void(base_size = 23) +
  theme(legend.position = "none", 
        # rect = element_rect(fill = "transparent"),
        plot.margin = unit(c(0, 2.3, 0, 2.3),"cm"),
        # plot.background = element_rect(fill = NULL)
        )

Time series

Daily

confirmed_cases %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  count(notification_date) %>% 
  ggplot(aes(x=notification_date , y=n)) + 
  # geom_point() + 
  geom_line() + 
  ylab("Count of cases") + 
  labs(subtitle = "Daily new confirmed Covid-19 cases (SYD)") + 
  annotate("text", x=ymd(20200505), y=60, size=3.3, col="darkred", 
           label="1st outbreak \n (Bondi beach, \nSouth Eastern \nSydney)") + 
  annotate("text", x=ymd(20200815), y=25, size=3.3, col="darkred", 
           label="2nd outbreak \n (Westmead & Liverpool, \nWestern Sydney)") + 
  annotate("text", x=ymd(20210101), y=35, size=3.3, col="darkred", 
           label="3rd outbreak \n (Avalon beach, Northern Sydney)") + 
  ggl()

confirmed_cases %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  count(lhd_2010_name, notification_date) %>% 
  ggplot(aes(x=notification_date , y=n, col=lhd_2010_name)) + 
  # geom_point() + 
  geom_line() + 
  # facet_wrap(~lhd_2010_name) + 
  labs(subtitle = "Daily new confirmed Covid-19 cases (SYD)") + 
  ggl(lp = "right")

Cumulative

confirmed_cases %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  mutate(lhd_2010_name = ifelse(lhd_2010_name == "Sydney", "Sydney (around CBD)", 
                                lhd_2010_name)) %>% 
  # mutate(lhd_2010_name = ifelse(is.na(lhd_2010_name), "Unknown", lhd_2010_name)) %>%
  count(lhd_2010_name, notification_date) %>% 
  group_by(lhd_2010_name) %>% 
  mutate(days_since_first_case = notification_date - min(notification_date)) %>% 
  mutate(accumulated_cases = cumsum(n)) %>% 
  mutate(lab = ifelse(notification_date == max(notification_date, na.rm=T), 
                      lhd_2010_name, NA)) %>% 
  
  ggplot(aes(x=notification_date , y=accumulated_cases, col=lhd_2010_name)) + 
  # geom_point() + 
  geom_line() + 
  geom_text_repel(aes(label=lab), size=4, hjust=-.1, min.segment.length = 10) + 
  # facet_wrap(~lhd_2010_name) + 
  labs(subtitle = "Accumulated confirmed Covid-19 cases (SYD), by region") + 
  # xlim(c(0,550)) +
  ggl(lp = "none") 

confirmed_cases %>% 
  mutate(lhd_2010_name = ifelse(lhd_2010_name == "Sydney", "Metro Sydney", 
                                lhd_2010_name)) %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  # filter(lhd_2010_name %in% c("South Eastern Sydney", 
  #                          "Northern Sydney", 
  #                          "Western Sydney", 
  #                          "South Western Sydney", 
  #                          "Sydney") | is.na(lhd_2010_name)) %>% 
  count(lhd_2010_name, postcode, notification_date) %>% 
  group_by(lhd_2010_name, postcode) %>% 
  mutate(days_since_first_case = notification_date - min(notification_date)) %>% 
  mutate(accumulated_cases = cumsum(n)) %>% 
  mutate(lab=ifelse(notification_date == max(notification_date), postcode, NA)) %>% 
  
  ggplot(aes(x=notification_date , y=accumulated_cases, 
             group=postcode,
             col=lhd_2010_name)) + 
  # geom_point() + 
  geom_line() + 
  geom_text(aes(label=lab), size=3, hjust="outward") + 
  facet_wrap(~lhd_2010_name) +
  labs(subtitle = "Accumulated confirmed Covid-19 cases (SYD), by postcode") + 
  # xlim(c(0,550)) +
  ggl(lp = "none", ) + 
  theme(strip.text.x = element_text(size = 12))

Map

Looks like each postcode (POA) can only belong to one LGA, which is not the case for SA2

confirmed_cases %>% 
  distinct(postcode, lga_name19) %>% 
  count(postcode) %>% 
  summarise(max(n)) %>% 
  pull()
[1] 1

LGA

confirmed_cases %>% 
  filter(lga_name19 %in% SYD_LGA$LGA_NAME19) %>% 
  count(lga_name19, name="Total_cases") %>% 
  rename(LGA_NAME19 = lga_name19) %>% 
  mutate(LGA_NAME19 = fct_reorder(LGA_NAME19, Total_cases)) %>% 
  plot_map_TL(SYD_LGA, "LGA_NAME19", "Total_cases", 
           "Total Covid-19 cases by LGA (SYD)", show_count = T)

POA

confirmed_cases %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  count(postcode, name="Total_cases") %>% 
  rename(POA_NAME16 = postcode) %>% 
  mutate(POA_NAME16 = fct_reorder(as.factor(POA_NAME16), Total_cases)) %>% 
  plot_map_TL(SYD_POA, "POA_NAME16", "Total_cases", 
           "Total Covid-19 cases by POA (SYD)", 
           show_count = T, label_size = 2)

confirmed_cases %>%
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>%
  count(postcode, name="Total_cases") %>%
  rename(POA_NAME16 = postcode) %>%
  mutate(POA_NAME16 = fct_reorder(as.factor(POA_NAME16), Total_cases)) %>%
  mutate(cluster_origin = ifelse(POA_NAME16 %in% c("2026", "2145", "2107"),
                                 "cluster_origin", "") %>% as.factor) %>%
  plot_map_factor_TL(SYD_POA, "POA_NAME16", "Total_cases", "cluster_origin",
              "Total Covid-19 cases by POA (SYD), highlighted by cluster origin",
              show_count = T, label_size = 2)

confirmed_cases %>% 
  filter(!(postcode %in% c(2026, 2145, 2170))) %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  count(postcode, name="Total_cases") %>% 
  rename(POA_NAME16 = postcode) %>% 
  mutate(POA_NAME16 = fct_reorder(as.factor(POA_NAME16), Total_cases)) %>% 
  plot_map_TL(SYD_POA, "POA_NAME16", "Total_cases", 
           "Total Covid-19 cases by POA (SYD), excluding top 3 POA", 
           show_count = T, label_size = 2)

Note

Northern Beaches has many postcodes which result in more diluted choropleth by POA.

confirmed_cases %>% 
  distinct(lga_name19, postcode) %>% 
  count(lga_name19, name="Number_of_postcodes") %>% 
  left_join(confirmed_cases %>% count(lga_name19, name="Total_cases"), 
            by="lga_name19") %>% 
  slice_max(n=30, order_by = Total_cases) %>% 
  gather(key, value, -lga_name19) %>% 
  ggplot(aes(x=reorder(lga_name19, value), y=value)) + 
  geom_col() + 
  facet_wrap(~key, scales = "free_x") + 
  coord_flip() + 
  xlab("") + ylab("") + 
  ggl()

Map overtime cumulative

By quarter

Accumulated cases

confirmed_cases %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  mutate(year_quarter = paste(year(notification_date), "Q",
                             quarter(notification_date), sep="-")) %>% 
  count(year_quarter, postcode, name="Total_cases") %>% 
  complete(year_quarter, postcode, fill = list(Total_cases=0)) %>% 
  group_by(postcode) %>% 
  mutate(Accumulated_cases = cumsum(Total_cases)) %>% 
  group_by(year_quarter) %>% 
  mutate(Accumulated_share = (Accumulated_cases/sum(Accumulated_cases, 
                                                    na.rm=T))) %>% 
  mutate(facet_var = paste0(year_quarter, 
                            "\nAccumulated: ", 
                            comma(sum(Accumulated_cases)))) %>% 
  rename(POA_NAME16 = postcode) %>% 
  
  plot_map_TL(rmapshaper::ms_simplify(
    SYD_POA[SYD_POA$POA_NAME16 %in% as.character(
      confirmed_cases$postcode) ,], .01), 
              "POA_NAME16", "Accumulated_cases", 
           "Total accumulated Covid-19 cases by POA (SYD), overtime", 
           return_obj="map") + 
  facet_wrap(~facet_var) + 
  theme_map_facet_TL

Accumulated share

confirmed_cases %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  mutate(year_quarter = paste(year(notification_date), "Q",
                             quarter(notification_date), sep="-")) %>% 
  count(year_quarter, postcode, name="Total_cases") %>% 
  complete(year_quarter, postcode, fill = list(Total_cases=0)) %>% 
  group_by(postcode) %>% 
  mutate(Accumulated_cases = cumsum(Total_cases)) %>% 
  group_by(year_quarter) %>% 
  mutate(Accumulated_share = (Accumulated_cases/sum(Accumulated_cases, 
                                                    na.rm=T))) %>%
  mutate(facet_var = paste0(year_quarter, 
                            "\nAccumulated: ", 
                            comma(sum(Accumulated_cases)))) %>% 
  rename(POA_NAME16 = postcode) %>% 
  
  plot_map_TL(rmapshaper::ms_simplify(
    SYD_POA[SYD_POA$POA_NAME16 %in% as.character(
      confirmed_cases$postcode) ,], .01), 
              "POA_NAME16", "Accumulated_share", 
           "Total Covid-19 cases by POA (SYD)", 
           return_obj="map") + 
  facet_wrap(~facet_var) + 
  theme_map_facet_TL

By week Mar-May 2020

Accumulated cases

confirmed_cases %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  filter(year(notification_date) == 2020, 
         # month(notification_date) %in% 3:5, 
         isoweek(notification_date) %in% 10:23) %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  mutate(isoweek = isoweek(notification_date)) %>% 
  count(isoweek, postcode, name="Total_cases") %>% 
  complete(isoweek, postcode, fill = list(Total_cases=0)) %>% 
  group_by(postcode) %>% 
  mutate(Accumulated_cases = cumsum(Total_cases)) %>% 
  group_by(isoweek) %>% 
  mutate(Accumulated_share = (Accumulated_cases/sum(Accumulated_cases, 
                                                    na.rm=T))) %>%
  mutate(facet_var = paste0("week ", isoweek, 
                            "\nAccumulated: ", 
                            comma(sum(Accumulated_cases)))) %>% 
  rename(POA_NAME16 = postcode) %>% 
  mutate(POA_NAME16 = fct_reorder(as.factor(POA_NAME16), Total_cases)) %>% 
  ungroup() %>% 
  filter(!is.na(isoweek)) %>% 
  
  plot_map_TL(rmapshaper::ms_simplify(SYD_POA, .01), 
              "POA_NAME16", "Accumulated_cases", 
              "Total Covid-19 cases by POA (SYD)", 
              return_obj="map") + 
  facet_wrap(~facet_var) + 
  theme_map_facet_TL + theme(legend.position = c(.83, .15))

Accumulated share

confirmed_cases %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  filter(year(notification_date) == 2020, 
         # month(notification_date) %in% 3:5, 
         isoweek(notification_date) %in% 10:23) %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  mutate(isoweek = isoweek(notification_date)) %>% 
  count(isoweek, postcode, name="Total_cases") %>% 
  complete(isoweek, postcode, fill = list(Total_cases=0)) %>% 
  group_by(postcode) %>% 
  mutate(Accumulated_cases = cumsum(Total_cases)) %>% 
  group_by(isoweek) %>% 
  mutate(Accumulated_share = (Accumulated_cases/sum(Accumulated_cases, na.rm=T))) %>% 
  rename(POA_NAME16 = postcode) %>% 
  mutate(POA_NAME16 = fct_reorder(as.factor(POA_NAME16), Total_cases)) %>% 
  mutate(facet_var = paste0("week ", isoweek, 
                            "\nAccumulated: ", 
                            comma(sum(Accumulated_cases)))) %>% 
  ungroup() %>% 
  filter(!is.na(isoweek)) %>% 
  
  plot_map_TL(rmapshaper::ms_simplify(SYD_POA, .01), 
              "POA_NAME16", "Accumulated_share", 
              "Total Covid-19 cases by POA (SYD)", 
              return_obj="map") + 
  facet_wrap(~facet_var) + 
  theme_map_facet_TL + theme(legend.position = c(.83, .15))

Distribution of share overtime

By quarter

confirmed_cases %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  mutate(year_quarter = paste(year(notification_date), "Q",
                             quarter(notification_date), sep="-")) %>% 
  count(year_quarter, postcode, name="Total_cases") %>% 
  complete(year_quarter, postcode, fill = list(Total_cases=0)) %>% 
  group_by(postcode) %>% 
  mutate(Accumulated_cases = cumsum(Total_cases)) %>% 
  ungroup() %>% 
  complete(year_quarter, postcode) %>% 
  replace_na(list(Accumulated_cases=0)) %>% 
  group_by(year_quarter) %>% 
  mutate(Accumulated_share = (Accumulated_cases/sum(Accumulated_cases, na.rm=T))) %>% 
  rename(POA_NAME16 = postcode) %>% 
  ungroup() %>% 
  
  ggplot(aes(x=year_quarter, y=Accumulated_cases, 
             fill=Accumulated_cases > 50,
             group=as.factor(POA_NAME16))) + 
  geom_col(col="white", size=.1) + 
  ggf(fc = DC[2:1]) + 
  ggl("top", lt = T)

confirmed_cases %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  mutate(year_quarter = paste(year(notification_date), "Q",
                             quarter(notification_date), sep="-")) %>% 
  count(year_quarter, postcode, name="Total_cases") %>% 
  group_by(postcode) %>% 
  mutate(Accumulated_cases = cumsum(Total_cases)) %>% 
  ungroup() %>% 
  complete(year_quarter, postcode) %>% 
  replace_na(list(Accumulated_cases=0)) %>% 
  group_by(year_quarter) %>% 
  mutate(Accumulated_share = (Accumulated_cases/sum(Accumulated_cases, na.rm=T))) %>% 
  rename(POA_NAME16 = postcode) %>% 
  
  ggplot(aes(x=Accumulated_share, fill=as.factor(year_quarter))) + 
  # geom_density() + 
  geom_histogram() + 
  facet_wrap(~year_quarter, nrow = 1) + 
  xlim(0,.03) + 
  ylim(0,40) +
  ggl("none")

By week

confirmed_cases %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  filter(year(notification_date) == 2020, 
         # month(notification_date) %in% 3:5, 
         isoweek(notification_date) %in% 10:23) %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  mutate(isoweek = isoweek(notification_date)) %>% 
  count(isoweek, postcode, name="Total_cases") %>% 
  complete(isoweek, postcode, fill = list(Total_cases=0)) %>% 
  group_by(postcode) %>% 
  mutate(Accumulated_cases = cumsum(Total_cases)) %>% 
  group_by(isoweek) %>% 
  mutate(Accumulated_share = (Accumulated_cases/sum(Accumulated_cases, 
                                                    na.rm=T))) %>%
  mutate(facet_var = paste0("week ", isoweek, 
                            "\nAccumulated: ", 
                            comma(sum(Accumulated_cases)))) %>% 
  rename(POA_NAME16 = postcode) %>% 
  mutate(POA_NAME16 = fct_reorder(as.factor(POA_NAME16), Total_cases)) %>% 
  ungroup() %>% 
  filter(!is.na(isoweek)) %>% 
  
  ggplot(aes(x=isoweek, y=Accumulated_cases, 
             fill=Accumulated_cases > 20,
             group=as.factor(POA_NAME16))) + 
  geom_col(col="white", size=.1) + 
  ggx(round, pbn=12) +
  ggf(fc = DC[2:1]) + 
  ggl("top", lt = T)

confirmed_cases %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  filter(year(notification_date) == 2020, 
         # month(notification_date) %in% 3:5, 
         isoweek(notification_date) %in% 10:23) %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  mutate(isoweek = isoweek(notification_date)) %>% 
  count(isoweek, postcode, name="Total_cases") %>% 
  complete(isoweek, postcode, fill = list(Total_cases=0)) %>% 
  group_by(postcode) %>% 
  mutate(Accumulated_cases = cumsum(Total_cases)) %>% 
  group_by(isoweek) %>% 
  mutate(Accumulated_share = (Accumulated_cases/sum(Accumulated_cases, 
                                                    na.rm=T))) %>%
  mutate(facet_var = paste0("week ", isoweek, 
                            "\nAccumulated: ", 
                            comma(sum(Accumulated_cases)))) %>% 
  rename(POA_NAME16 = postcode) %>% 
  mutate(POA_NAME16 = fct_reorder(as.factor(POA_NAME16), Total_cases)) %>% 
  ungroup() %>% 
  filter(!is.na(isoweek)) %>% 
  
  ggplot(aes(x=Accumulated_share, fill=as.factor(isoweek))) + 
  # geom_density() + 
  geom_histogram() + 
  facet_wrap(~isoweek, nrow = 3, labeller = "label_both") + 
  xlim(0,.03) + 
  ylim(0,40) +
  ggl("none")

Local POI

Public transport

confirmed_cases %>% 
    filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
    count(postcode, name="Total_cases") %>% 
    rename(POA_NAME16 = postcode) %>% 
    mutate(POA_NAME16 = fct_reorder(as.factor(POA_NAME16), Total_cases)) %>% 
    plot_map_TL(SYD_POA, "POA_NAME16", "Total_cases", fill_col = "grey33",
                "Total Covid-19 cases by POA (SYD), with public transport", 
                show_count = T, label_size = 2, return_obj = "map") +
  
  # geom_map(inherit.aes = FALSE, alpha=.85,
  #          aes(map_id = id), map = tidy(SYD_POA), 
  #          col="grey50", size=.3, fill="white") +
  geom_line(data = SYD_trains, 
            aes(x=lon, y=lat, col="Train",
                group = `Railway line(s)`),
            size=.8) +
  geom_line(data = SYD_ferries, 
            aes(x=lon, y=lat, col="Ferry"),
             size=.8) +
  geom_line(data = SYD_lightrails, 
            aes(x=lon, y=lat, col="Lightrail"),
             size=.8) +
  geom_line(data = SYD_metro, 
            aes(x=lon, y=lat, col="Metro"),
             size=.8) +
  ggc(c("deepskyblue", "red", "darkgreen", "orange")) + 
  guides(col=guide_legend(title="Transport_mode")) + 
  expand_limits(x = tidy(SYD_POA)$long, y = tidy(SYD_POA)$lat) +
  coord_cartesian(xlim = c(150.7, 151.48), ylim = c(-34.1, -33.5)) +
  theme_void() +
  theme(legend.position = c(.9,.35))

Hospitals, Schools, Supermarket

bind_rows(
  SYD_shops %>% select(lon, lat) %>% 
    rename(Long = lon, Lat = lat) %>% mutate(obj = "Shopping centres"), 
  SYD_supermarkets %>% select(lon, lat) %>% 
    rename(Long = lon, Lat = lat) %>% mutate(obj = "Supermarkets"), 
  SYD_hospitals %>% select(Longitude, Latitude) %>% 
    rename(Long = Longitude, Lat = Latitude) %>% mutate(obj = "Hospitals"), 
  rbind(SYD_sschools %>% select(Long, Lat),
        SYD_pschools %>% select(Long, Lat)) %>% mutate(obj = "Schools")
) %>% 
  ggplot() +  
  geom_map(data = SYD_POA, inherit.aes = FALSE, alpha=.85,
           aes(map_id = id), map = tidy(SYD_POA), 
           col="grey50", size=.2, fill="white") +
  geom_jitter(aes(x=Long, y=Lat, col=obj), size=.8, alpha=.5) + 
  stat_density2d(aes(x=Long, y=Lat, 
                     fill=..level.., alpha=..level.., col=obj),
                 binwidth = 1.2, geom="polygon", size=.23) + 
  facet_wrap(~obj) +
  expand_limits(x = tidy(SYD_POA)$long, y = tidy(SYD_POA)$lat) +
  xlim(150.7,151.48) + ylim(-34.1,-33.5) +
  scale_fill_gradient(low="white", high=DC[7]) + 
  scale_alpha_continuous(range = c(0,.3)) + 
  ggc(fc = c("darkred", "deepskyblue", "darkblue", "darkgreen")) + 
  theme_void() +
  theme(legend.position = "none", 
        legend.title = element_blank(), 
        strip.text = element_text(size=15))

confirmed_cases %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  count(postcode, name="Total_cases") %>% 
  rename(POA_NAME16 = postcode) %>% 
  mutate(POA_NAME16 = fct_reorder(as.factor(POA_NAME16), Total_cases)) %>% 
  plot_map_TL(SYD_POA, "POA_NAME16", "Total_cases", fill_col = "grey33",
              "Total Covid-19 cases by POA (SYD), with hospitals, schools & supermarkets", 
              show_count = T, label_size = 2, return_obj = "map") +
  
  # geom_map(data = SYD_POA, inherit.aes = FALSE, alpha=.85,
  #          aes(map_id = id), map = tidy(SYD_POA), 
  #          col="grey50", size=.3, fill="white") +
  geom_jitter(data = bind_rows(
    SYD_shops %>% select(lon, lat) %>% 
      rename(Long = lon, Lat = lat) %>% mutate(obj = "Shopping centres"), 
    SYD_supermarkets %>% select(lon, lat) %>% 
      rename(Long = lon, Lat = lat) %>% mutate(obj = "Supermarkets"), 
    SYD_hospitals %>% select(Longitude, Latitude) %>% 
      rename(Long = Longitude, Lat = Latitude) %>% mutate(obj = "Hospitals"), 
    rbind(SYD_sschools %>% select(Long, Lat),
          SYD_pschools %>% select(Long, Lat)) %>% mutate(obj = "Schools")
  ), 
  size = 1, alpha = .3, aes(x=Long, y=Lat,col=obj)) +
  expand_limits(x = tidy(SYD_POA)$long, y = tidy(SYD_POA)$lat) +
  xlim(150.7,151.48) + ylim(-34.1,-33.5) +
  # scale_fill_gradient(low="white", high=DC[7]) + 
  scale_alpha_continuous(range = c(0,.3)) + 
  ggc(fc = c("darkred", "darkblue", "darkorange", "darkgreen")) + 
  guides(color = guide_legend(override.aes = list(size=3), 
                              title="POI")) + 
  theme_void() +
  theme(legend.position = c(.9,.25), 
        # legend.title = element_blank(), 
        strip.text = element_text(size=15))

POI combined

confirmed_cases %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  count(postcode, name="Total_cases") %>% 
  rename(POA_NAME16 = postcode) %>% 
  mutate(POA_NAME16 = fct_reorder(as.factor(POA_NAME16), Total_cases)) %>% 
  plot_map_TL(SYD_POA, "POA_NAME16", "Total_cases", fill_col = "grey33",
              "Total Covid-19 cases by POA (SYD), with hospitals, schools & supermarkets", 
              show_count = T, label_size = 2, return_obj = "map") +
  geom_line(data = SYD_trains, 
            aes(x=lon, y=lat, col="Train",
                group = `Railway line(s)`),
            size=.8) +
  geom_line(data = SYD_ferries, 
            aes(x=lon, y=lat, col="Ferry"),
             size=.8) +
  geom_line(data = SYD_lightrails, 
            aes(x=lon, y=lat, col="Lightrail"),
             size=.8) +
  geom_line(data = SYD_metro, 
            aes(x=lon, y=lat, col="Metro"),
             size=.8) +
  
  # geom_map(data = SYD_POA, inherit.aes = FALSE, alpha=.85,
  #          aes(map_id = id), map = tidy(SYD_POA), 
  #          col="grey50", size=.3, fill="white") +
  geom_jitter(data = bind_rows(
    SYD_shops %>% select(lon, lat) %>% 
      rename(Long = lon, Lat = lat) %>% mutate(obj = "Shopping centres"), 
    SYD_supermarkets %>% select(lon, lat) %>% 
      rename(Long = lon, Lat = lat) %>% mutate(obj = "Supermarkets"), 
    SYD_hospitals %>% select(Longitude, Latitude) %>% 
      rename(Long = Longitude, Lat = Latitude) %>% mutate(obj = "Hospitals"), 
    rbind(SYD_sschools %>% select(Long, Lat),
          SYD_pschools %>% select(Long, Lat)) %>% mutate(obj = "Schools")
  ), 
  size = 1, alpha = .3, aes(x=Long, y=Lat,col=obj)) +
  expand_limits(x = tidy(SYD_POA)$long, y = tidy(SYD_POA)$lat) +
  xlim(150.7,151.48) + ylim(-34.1,-33.5) +
  # scale_fill_gradient(low="white", high=DC[7]) + 
  scale_alpha_continuous(range = c(0,.3)) + 
  ggc(fc = c("deepskyblue", "darkblue", "red", "darkgreen", 
             "darkblue", "red", "darkgreen", "orange")) + 
  guides(color = guide_legend(override.aes = list(size=3), 
                              title="POI")) + 
  theme_void() +
  theme(legend.position = c(.9,.4), 
        # legend.title = element_blank(), 
        strip.text = element_text(size=15))

POI count QA

Hospital

n_poi_by_POA %>% 
  filter(POA_NAME16 != "Unknown") %>% 
  # gather(key, value, -POA_NAME16) %>% 
  select(POA_NAME16, n_hospitals) %>% 
  mutate(POA_NAME16 = fct_reorder(POA_NAME16, n_hospitals)) %>% 
  plot_map_TL(SYD_POA, "POA_NAME16", "n_hospitals", 
              "Number of hospitals by POA", 
              show_count = T, fill_col = "darkred")

Schools

n_poi_by_POA %>% 
  filter(POA_NAME16 != "Unknown") %>% 
  # gather(key, value, -POA_NAME16) %>% 
  select(POA_NAME16, n_schools) %>% 
  mutate(POA_NAME16 = fct_reorder(POA_NAME16, n_schools)) %>% 
  plot_map_TL(SYD_POA, "POA_NAME16", "n_schools", 
              "Number of schools by POA", 
              show_count = T, fill_col = "deepskyblue")

Supermarkets

n_poi_by_POA %>% 
  filter(POA_NAME16 != "Unknown") %>% 
  # gather(key, value, -POA_NAME16) %>% 
  select(POA_NAME16, n_supermarkets) %>% 
  mutate(POA_NAME16 = fct_reorder(POA_NAME16, n_supermarkets)) %>% 
  plot_map_TL(SYD_POA, "POA_NAME16", "n_supermarkets", 
              "Number of supermarkets by POA", 
              show_count = T, fill_col = "darkgreen")

Shopping centres

n_poi_by_POA %>% 
  filter(POA_NAME16 != "Unknown") %>% 
  # gather(key, value, -POA_NAME16) %>% 
  select(POA_NAME16, n_shoppingCentres) %>% 
  mutate(POA_NAME16 = fct_reorder(POA_NAME16, n_shoppingCentres)) %>% 
  plot_map_TL(SYD_POA, "POA_NAME16", "n_shoppingCentres", 
              "Number of shopping centres by POA", 
              show_count = T, fill_col = "black")

Public transports

n_poi_by_POA %>% 
  filter(POA_NAME16 != "Unknown") %>% 
  # gather(key, value, -POA_NAME16) %>% 
  select(POA_NAME16, n_publicTransports ) %>% 
  mutate(POA_NAME16 = fct_reorder(POA_NAME16, n_publicTransports )) %>% 
  plot_map_TL(SYD_POA, "POA_NAME16", "n_publicTransports", 
              "Number of public transports by POA", 
              show_count = T, fill_col = "darkorange")

Gravity

South Eastern SYD (2026)

Radial distance

(
plot_gravity_map_TL(n_poi_by_POA, "2026", "n_hospitals") + 
  xlim(151.1,151.33) + ylim(-34,-33.7) | 
plot_gravity_map_TL(n_poi_by_POA, "2026", "n_schools") + 
  xlim(151.1,151.33) + ylim(-34,-33.7) |
plot_gravity_map_TL(n_poi_by_POA, "2026", "n_supermarkets") + 
  xlim(151.1,151.33) + ylim(-34,-33.7)
) /
(
plot_gravity_map_TL(n_poi_by_POA, "2026", "n_shoppingCentres") + 
  xlim(151.1,151.33) + ylim(-34,-33.7) | 
plot_gravity_map_TL(n_poi_by_POA, "2026", "n_publicTransports") + 
  xlim(151.1,151.33) + ylim(-34,-33.7) | 
n_poi_by_POA %>% 
  mutate(combined_index = 
           normalised_n_hospitals +
           normalised_n_schools +
           normalised_n_supermarkets +
           normalised_n_shoppingCentres +
           normalised_n_publicTransports
  ) %>% plot_gravity_map_TL("2026", "combined_index") + 
  xlim(151.1,151.33) + ylim(-34,-33.7)
)

Travel time distance

(
plot_gravity_map_TL(n_poi_by_POA, "2026", "n_hospitals", 
                    dist_matrix = SYD_POA_mapdist %>% mutate(dist = dist/1000)) + 
  xlim(151.1,151.33) + ylim(-34,-33.7) | 
plot_gravity_map_TL(n_poi_by_POA, "2026", "n_schools", 
                    dist_matrix = SYD_POA_mapdist %>% mutate(dist = dist/1000)) + 
  xlim(151.1,151.33) + ylim(-34,-33.7) |
plot_gravity_map_TL(n_poi_by_POA, "2026", "n_supermarkets", 
                    dist_matrix = SYD_POA_mapdist %>% mutate(dist = dist/1000)) + 
  xlim(151.1,151.33) + ylim(-34,-33.7)
) /
(
plot_gravity_map_TL(n_poi_by_POA, "2026", "n_shoppingCentres", 
                    dist_matrix = SYD_POA_mapdist %>% mutate(dist = dist/1000)) + 
  xlim(151.1,151.33) + ylim(-34,-33.7) | 
plot_gravity_map_TL(n_poi_by_POA, "2026", "n_publicTransports", 
                    dist_matrix = SYD_POA_mapdist %>% mutate(dist = dist/1000)) + 
  xlim(151.1,151.33) + ylim(-34,-33.7) | 
n_poi_by_POA %>% 
  mutate(combined_index = 
           normalised_n_hospitals +
           normalised_n_schools +
           normalised_n_supermarkets +
           normalised_n_shoppingCentres +
           normalised_n_publicTransports
  ) %>% plot_gravity_map_TL("2026", "combined_index", 
                    dist_matrix = SYD_POA_mapdist %>% mutate(dist = dist/1000)) + 
  xlim(151.1,151.33) + ylim(-34,-33.7)
)

Western SYD (2145)

Radial distance

(
plot_gravity_map_TL(n_poi_by_POA, "2145", "n_hospitals") | 
plot_gravity_map_TL(n_poi_by_POA, "2145", "n_schools") |
plot_gravity_map_TL(n_poi_by_POA, "2145", "n_supermarkets")
) /
(
plot_gravity_map_TL(n_poi_by_POA, "2145", "n_shoppingCentres") | 
plot_gravity_map_TL(n_poi_by_POA, "2145", "n_publicTransports") | 
n_poi_by_POA %>% 
  mutate(combined_index = 
           normalised_n_hospitals +
           normalised_n_schools +
           normalised_n_supermarkets +
           normalised_n_shoppingCentres +
           normalised_n_publicTransports
  ) %>% plot_gravity_map_TL("2145", "combined_index")
)

Travel time distance

(
plot_gravity_map_TL(n_poi_by_POA, "2145", "n_hospitals", 
                    dist_matrix = SYD_POA_mapdist %>% mutate(dist = dist/1000)) | 
plot_gravity_map_TL(n_poi_by_POA, "2145", "n_schools", 
                    dist_matrix = SYD_POA_mapdist %>% mutate(dist = dist/1000)) |
plot_gravity_map_TL(n_poi_by_POA, "2145", "n_supermarkets", 
                    dist_matrix = SYD_POA_mapdist %>% mutate(dist = dist/1000))
) /
(
plot_gravity_map_TL(n_poi_by_POA, "2145", "n_shoppingCentres", 
                    dist_matrix = SYD_POA_mapdist %>% mutate(dist = dist/1000)) | 
plot_gravity_map_TL(n_poi_by_POA, "2145", "n_publicTransports", 
                    dist_matrix = SYD_POA_mapdist %>% mutate(dist = dist/1000)) | 
n_poi_by_POA %>% 
  mutate(combined_index = 
           normalised_n_hospitals +
           normalised_n_schools +
           normalised_n_supermarkets +
           normalised_n_shoppingCentres +
           normalised_n_publicTransports
  ) %>% plot_gravity_map_TL("2145", "combined_index", 
                    dist_matrix = SYD_POA_mapdist %>% mutate(dist = dist/1000))
)

Nothern SYD (2107)

Radial distance

(
plot_gravity_map_TL(n_poi_by_POA, "2107", "n_hospitals") + 
  xlim(151,151.4) + ylim(-33.9,-33.5) | 
plot_gravity_map_TL(n_poi_by_POA, "2107", "n_schools") + 
  xlim(151,151.4) + ylim(-33.9,-33.5) |
plot_gravity_map_TL(n_poi_by_POA, "2107", "n_supermarkets") + 
  xlim(151,151.4) + ylim(-33.9,-33.5)
) /
(
plot_gravity_map_TL(n_poi_by_POA, "2107", "n_shoppingCentres") + 
  xlim(151,151.4) + ylim(-33.9,-33.5) | 
plot_gravity_map_TL(n_poi_by_POA, "2107", "n_publicTransports") + 
  xlim(151,151.4) + ylim(-33.9,-33.5) | 
n_poi_by_POA %>% 
  mutate(combined_index = 
           normalised_n_hospitals +
           normalised_n_schools +
           normalised_n_supermarkets +
           normalised_n_shoppingCentres +
           normalised_n_publicTransports
  ) %>% plot_gravity_map_TL("2107", "combined_index") + 
  xlim(151,151.4) + ylim(-33.9,-33.5)
)

Travel time distance

(
plot_gravity_map_TL(n_poi_by_POA, "2107", "n_hospitals", 
                    dist_matrix = SYD_POA_mapdist %>% mutate(dist = dist/1000)) + 
  xlim(151,151.4) + ylim(-33.9,-33.5) | 
plot_gravity_map_TL(n_poi_by_POA, "2107", "n_schools", 
                    dist_matrix = SYD_POA_mapdist %>% mutate(dist = dist/1000)) + 
  xlim(151,151.4) + ylim(-33.9,-33.5) |
plot_gravity_map_TL(n_poi_by_POA, "2107", "n_supermarkets", 
                    dist_matrix = SYD_POA_mapdist %>% mutate(dist = dist/1000)) + 
  xlim(151,151.4) + ylim(-33.9,-33.5)
) /
(
plot_gravity_map_TL(n_poi_by_POA, "2107", "n_shoppingCentres", 
                    dist_matrix = SYD_POA_mapdist %>% mutate(dist = dist/1000)) + 
  xlim(151,151.4) + ylim(-33.9,-33.5) | 
plot_gravity_map_TL(n_poi_by_POA, "2107", "n_publicTransports", 
                    dist_matrix = SYD_POA_mapdist %>% mutate(dist = dist/1000)) + 
  xlim(151,151.4) + ylim(-33.9,-33.5) | 
n_poi_by_POA %>% 
  mutate(combined_index = 
           normalised_n_hospitals +
           normalised_n_schools +
           normalised_n_supermarkets +
           normalised_n_shoppingCentres +
           normalised_n_publicTransports
  ) %>% plot_gravity_map_TL("2107", "combined_index", 
                    dist_matrix = SYD_POA_mapdist %>% mutate(dist = dist/1000)) + 
  xlim(151,151.4) + ylim(-33.9,-33.5)
)

Suggested “high-risk” area

South Eastern SYD (2026)

bind_rows(
calc_gravity_TL(n_poi_by_POA, "2026", "n_hospitals", 
                    dist_matrix = SYD_POA_mapdist %>% mutate(dist = dist/1000))
,calc_gravity_TL(n_poi_by_POA, "2026", "n_schools", 
                    dist_matrix = SYD_POA_mapdist %>% mutate(dist = dist/1000))
,calc_gravity_TL(n_poi_by_POA, "2026", "n_supermarkets", 
                    dist_matrix = SYD_POA_mapdist %>% mutate(dist = dist/1000))
,calc_gravity_TL(n_poi_by_POA, "2026", "n_shoppingCentres", 
                    dist_matrix = SYD_POA_mapdist %>% mutate(dist = dist/1000))
,calc_gravity_TL(n_poi_by_POA, "2026", "n_publicTransports", 
                    dist_matrix = SYD_POA_mapdist %>% mutate(dist = dist/1000))
) %>% 
  group_by(target, source) %>% 
  summarise(risk_factor = sum(gravity_rank)) %>% 
  # slice_max(risk_factor, n=11) %>% 
  # pdf()
  
  left_join(
    confirmed_cases %>% 
      filter(notification_date < ymd(20200701)) %>% 
      count(postcode, name = "total_cases") %>% 
      mutate(source = as.character(postcode)), 
    by="source"
  ) %>% 
  mutate(text_lab = ifelse(total_cases >= 30, source, NA)) %>% 
  ggplot(aes(x=risk_factor, y=total_cases)) + 
  geom_point() + 
  stat_smooth() + 
  geom_text_repel(aes(label=text_lab)) + 
  labs(subtitle = "Based on total cases before date 2020-07-01") + 
  ggl(base_size=12)

Western SYD (2145)

bind_rows(
calc_gravity_TL(n_poi_by_POA, "2145", "n_hospitals", 
                    dist_matrix = SYD_POA_mapdist %>% mutate(dist = dist/1000))
,calc_gravity_TL(n_poi_by_POA, "2145", "n_schools", 
                    dist_matrix = SYD_POA_mapdist %>% mutate(dist = dist/1000))
,calc_gravity_TL(n_poi_by_POA, "2145", "n_supermarkets", 
                    dist_matrix = SYD_POA_mapdist %>% mutate(dist = dist/1000))
,calc_gravity_TL(n_poi_by_POA, "2145", "n_shoppingCentres", 
                    dist_matrix = SYD_POA_mapdist %>% mutate(dist = dist/1000))
,calc_gravity_TL(n_poi_by_POA, "2145", "n_publicTransports", 
                    dist_matrix = SYD_POA_mapdist %>% mutate(dist = dist/1000))
) %>% 
  group_by(target, source) %>% 
  summarise(risk_factor = sum(gravity_rank)) %>% 
  # slice_max(risk_factor, n=11) %>%
  # pdf()
  left_join(
    confirmed_cases %>% 
      filter(notification_date >= ymd(20200701), 
             notification_date < ymd(20201101)) %>% 
      count(postcode, name = "total_cases") %>% 
      mutate(source = as.character(postcode)), 
    by="source"
  ) %>% 
  mutate(text_lab = ifelse(total_cases >= 15, source, NA)) %>% 
  ggplot(aes(x=risk_factor, y=total_cases)) + 
  geom_point() + 
  stat_smooth() + 
  geom_text_repel(aes(label=text_lab)) + 
  labs(subtitle = "Based on total cases between date 2020-07-01 and 2020-12-01") + 
  ggl(base_size=12)

Nothern SYD (2107)

bind_rows(
calc_gravity_TL(n_poi_by_POA, "2107", "n_hospitals", 
                    dist_matrix = SYD_POA_mapdist %>% mutate(dist = dist/1000))
,calc_gravity_TL(n_poi_by_POA, "2107", "n_schools", 
                    dist_matrix = SYD_POA_mapdist %>% mutate(dist = dist/1000))
,calc_gravity_TL(n_poi_by_POA, "2107", "n_supermarkets", 
                    dist_matrix = SYD_POA_mapdist %>% mutate(dist = dist/1000))
,calc_gravity_TL(n_poi_by_POA, "2107", "n_shoppingCentres", 
                    dist_matrix = SYD_POA_mapdist %>% mutate(dist = dist/1000))
,calc_gravity_TL(n_poi_by_POA, "2107", "n_publicTransports", 
                    dist_matrix = SYD_POA_mapdist %>% mutate(dist = dist/1000))
) %>% 
  group_by(target, source) %>% 
  summarise(risk_factor = sum(gravity_rank)) %>% 
  # slice_max(risk_factor, n=11) %>% 
  # pdf()
  left_join(
    confirmed_cases %>% 
      filter(notification_date >= ymd(20201101)) %>% 
      count(postcode, name = "total_cases") %>% 
      mutate(source = as.character(postcode)), 
    by="source"
  ) %>% 
  mutate(text_lab = ifelse(total_cases >= 15, source, NA)) %>% 
  ggplot(aes(x=risk_factor, y=total_cases)) + 
  geom_point() + 
  stat_smooth() + 
  geom_text_repel(aes(label=text_lab)) +
  labs(subtitle = "Based on total cases after date 2020-12-01") + 
  ggl(base_size=12)

Gravity parameters

SYD_POA_mapdist %>% 
  filter(target == "2145") %>% 
  left_join(n_poi_by_POA, by=c("source"="POA_NAME16")) %>% 
  left_join(n_poi_by_POA %>% filter(POA_NAME16 == "2145"), 
            suffix = c("","_target"), 
            by=c("target"="POA_NAME16")) %>% 
  left_join(confirmed_cases %>% 
              filter(notification_date >= ymd(20200701), 
                     notification_date < ymd(20201101)) %>% 
              count(postcode, name="Total_cases") %>% 
              mutate(source = as.character(postcode)), by="source") %>% 
  mutate(total_normalised_mass_source = 
           normalised_n_hospitals + 
           normalised_n_schools + 
           normalised_n_supermarkets + 
           normalised_n_shoppingCentres + 
           normalised_n_publicTransports) %>% 

  lm(log(Total_cases + 0.01) ~ 
       # log(total_normalised_mass_source + 0.01) + 
       log(n_hospitals + 0.01) +
       log(n_schools + 0.01) +
       log(n_supermarkets + 0.01) +
       log(n_shoppingCentres + 0.01) +
       log(n_publicTransports + 0.01) +
       log(n_hospitals + 0.01) +
       log(dist + 0.01), data=.) %>% 
  summary()

Call:
lm(formula = log(Total_cases + 0.01) ~ log(n_hospitals + 0.01) + 
    log(n_schools + 0.01) + log(n_supermarkets + 0.01) + log(n_shoppingCentres + 
    0.01) + log(n_publicTransports + 0.01) + log(n_hospitals + 
    0.01) + log(dist + 0.01), data = .)

Residuals:
     Min       1Q   Median       3Q      Max 
-1.46174 -0.64127 -0.08704  0.46585  1.97683 

Coefficients:
                                Estimate Std. Error t value Pr(>|t|)    
(Intercept)                     1.657080   0.432004   3.836 0.000213 ***
log(n_hospitals + 0.01)        -0.027305   0.035916  -0.760 0.448784    
log(n_schools + 0.01)           0.230516   0.103446   2.228 0.027967 *  
log(n_supermarkets + 0.01)      0.062173   0.040671   1.529 0.129319    
log(n_shoppingCentres + 0.01)  -0.004801   0.041027  -0.117 0.907070    
log(n_publicTransports + 0.01) -0.052132   0.035630  -1.463 0.146386    
log(dist + 0.01)               -0.378727   0.097518  -3.884 0.000179 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.843 on 106 degrees of freedom
  (101 observations deleted due to missingness)
Multiple R-squared:  0.224, Adjusted R-squared:  0.1801 
F-statistic: 5.099 on 6 and 106 DF,  p-value: 0.0001232
LS0tDQp0aXRsZTogIlNZRCBDb3ZpZC0xOSBjYXNlcyBFREEiDQphdXRob3I6ICJUb255IExpdSINCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCINCm91dHB1dDoNCiAgaHRtbF9ub3RlYm9vazoNCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUNCiAgICBoaWdobGlnaHQ6IHplbmJ1cm4NCiAgICB0aGVtZTogZmxhdGx5DQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZmxvYXQ6DQogICAgICBjb2xsYXBzZWQ6IG5vDQogIHBkZl9kb2N1bWVudDoNCiAgICB0b2M6IHllcw0KLS0tDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0Kb3B0aW9ucyhzY2lwZW49OTk5LCBleHByZXNzaW9ucz01MDAwMCwgDQogICAgICAgIERULm9wdGlvbnMgPSBsaXN0KHBhZ2VMZW5ndGggPSA4LA0KICAgICAgICAgICAgICAgICAgICAgICAgICBzY3JvbGxYID0gVFJVRSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgZG9tID0gJ0JmcnRpcCcsDQogICAgICAgICAgICAgICAgICAgICAgICAgIGJ1dHRvbnMgPSBjKCdjb3B5JywgJ2NzdicsICdleGNlbCcsICdwZGYnLCAncHJpbnQnKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgIGF1dG9XaWR0aCA9IFRSVUUpKSANCg0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBULCBtZXNzYWdlPUYsIHdhcm5pbmc9RiwgZmlnLndpZHRoPTkuNSwgZmlnLmhlaWdodD00KQ0Ka25pdHI6Om9wdHNfa25pdCRzZXQoZGV2LmFyZ3MgPSBsaXN0KHR5cGUgPSAiY2Fpcm8iKSwgcHJvZ3Jlc3M9RkFMU0UpDQpgYGANCg0KYGBge3J9DQojIHNvdXJjZSgidXRpbGl0eS5SIikNCnNvdXJjZSgiUl9mdW5jdGlvbnMuUiIpDQpzb3VyY2UoIlJfZGF0YV9wcmVwb2Nlc3NpbmcuUiIpDQpgYGANCg0KDQojIE5ld3MgaGVhZGxpbmUgey50YWJzZXR9DQojIyAxc3QgaGFsZiAyMDIwDQoNCmBgYHtyLCBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9MTJ9DQpBVV90aW1lbGluZSAlPiUgDQogIGZpbHRlcihkYXRlIDw9IHltZCgyMDIwMDUxNSkpICU+JQ0KICBhcnJhbmdlKGRhdGUpICU+JSANCiAgIyBmaWx0ZXIobmNoYXIoZXZlbnQpIDwgMjMwKSAlPiUgDQogICMgZmlsdGVyKHJlZ2lvbiAhPSAiVklDIikgJT4lIA0KICBtdXRhdGUocm93aWQgPSBhcy5udW1lcmljKHJvd25hbWVzKC4pKSkgJT4lIA0KICBtdXRhdGUoZGF0ZV9nYXAgPSBhcy5udW1lcmljKGRhdGUtbGFnKGRhdGUpKSkgJT4lIA0KICBtdXRhdGUobmNoYXIgPSBuY2hhcihldmVudCksIA0KICAgICAgICAgbmNoYXJfc2NhbGVkID0gKG5jaGFyLW1pbihuY2hhcikpLyhtYXgobmNoYXIpLW1pbihuY2hhcikpLCANCiAgICAgICAgICMgcG9pbnRfcG9zaXRpb24gPSA3MDAgKiBuY2hhcl9zY2FsZWQgKiAoLTEpXnJvd2lkLA0KICAgICAgICAgcG9pbnRfcG9zaXRpb24gPSBjKDEwMCwxMDAsMjgwLDMyMCw1NTAsMjAsMTAwLDU1MCw3MjAsMTUwLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIDI0MCw4ODAsNDAwLDMwMCkqKC0xKV5yb3dpZA0KICAgICAgICAgKSAlPiUgDQogIG11dGF0ZShmYWNldF92YXIgPSBxdWFydGVyKGRhdGUsIHdpdGhfeWVhciA9IFQpKSAlPiUgDQogIA0KICBnZ3Bsb3QoYWVzKHg9ZGF0ZSwgeT0wKSkgKyANCiAgZ2VvbV9saW5lKCkgKyANCiAgZ2VvbV9wb2ludChhZXMoY29sPXJlZ2lvbikpICsNCiAgZ2VvbV9zZWdtZW50KGFlcyh4PWRhdGUsIHhlbmQ9ZGF0ZSwgY29sPXJlZ2lvbiwNCiAgICAgICAgICAgICAgICAgICB5PTAsIHllbmQ9cG9pbnRfcG9zaXRpb24pKSArDQogIGdlb21fcG9pbnQoYWVzKHk9cG9pbnRfcG9zaXRpb24sIGNvbD1yZWdpb24pLCBzaGFwZT0xKSArDQogIGdlb21fdGV4dChhZXMoeT0tMTAsIA0KICAgICAgICAgICAgICAgIGxhYmVsPXBhc3RlMChkYXkoZGF0ZSksICIgIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1vbnRoKGRhdGUsIGxhYmVsPVQpKSksIA0KICAgICAgICAgICAgYW5nbGU9MzAsIA0KICAgICAgICAgICAgdmp1c3Q9MSwgaGp1c3Q9MSkgKyANCiAgZ2VvbV9sYWJlbChhZXMobGFiZWw9c3RyX3dyYXAocGFzdGUwKGRhdGUsICI6ICIsIGV2ZW50KSwgbmNoYXIvMS44KSwgYWxwaGE9LjcsDQogICAgICAgICAgICAgICAgICMgZGlyZWN0aW9ucz0ieSIsIG1pbi5zZWdtZW50Lmxlbmd0aCA9IEluZiwNCiAgICAgICAgICAgICAgICAgeD1kYXRlLCB5PXBvaW50X3Bvc2l0aW9uLCBjb2w9cmVnaW9uLCB2anVzdD0ib3V0d2FyZCIpKSArDQogIHNjYWxlX3hfZGF0ZShkYXRlX2JyZWFrcyA9ICIxIG1vbnRoIiwgDQogICAgICAgICAgICAgICBkYXRlX2xhYmVscyA9ICIlYiAlWSIpICsgDQogICMgZmFjZXRfd3JhcCh+ZmFjZXRfdmFyLCBzdHJpcC5wb3NpdGlvbj0idG9wIiwNCiAgIyAgICAgICAgICAgIG5jb2wgPSAxLCBzY2FsZXMgPSAiZnJlZV94IikgKw0KICAjIGNvb3JkX2ZsaXAoKSArDQogIHlsaW0oLTEyMDAsMTIwMCkgKyANCiAgY29vcmRfY2FydGVzaWFuKGNsaXAgPSAib2ZmIikgKyANCiAgbGFicyhzdWJ0aXRsZSA9ICJBVS9OU1cgQ292aWQtMTkgdGltZWxpbmUsIDFzdCBoYWxmIDIwMjAiKSArDQogIHRoZW1lX3ZvaWQoYmFzZV9zaXplID0gMjMpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLCANCiAgICAgICAgIyByZWN0ID0gZWxlbWVudF9yZWN0KGZpbGwgPSAidHJhbnNwYXJlbnQiKSwNCiAgICAgICAgcGxvdC5tYXJnaW4gPSB1bml0KGMoMCwgMi4zLCAwLCAyLjMpLCJjbSIpLA0KICAgICAgICAjIHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gTlVMTCkNCiAgICAgICAgKQ0KYGBgDQoNCiMjIDJuZCBoYWxmIDIwMjANCg0KYGBge3IsIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD0xMn0NCkFVX3RpbWVsaW5lICU+JSANCiAgZmlsdGVyKGRhdGUgPiB5bWQoMjAyMDA1MTUpKSAlPiUNCiAgYXJyYW5nZShkYXRlKSAlPiUgDQogICMgZmlsdGVyKG5jaGFyKGV2ZW50KSA8IDIzMCkgJT4lIA0KICAjIGZpbHRlcihyZWdpb24gIT0gIlZJQyIpICU+JSANCiAgbXV0YXRlKHJvd2lkID0gYXMubnVtZXJpYyhyb3duYW1lcyguKSkpICU+JSANCiAgbXV0YXRlKGRhdGVfZ2FwID0gYXMubnVtZXJpYyhkYXRlLWxhZyhkYXRlKSkpICU+JSANCiAgbXV0YXRlKG5jaGFyID0gbmNoYXIoZXZlbnQpLCANCiAgICAgICAgIG5jaGFyX3NjYWxlZCA9IChuY2hhci1taW4obmNoYXIpKS8obWF4KG5jaGFyKS1taW4obmNoYXIpKSwgDQogICAgICAgICAjIHBvaW50X3Bvc2l0aW9uID0gNzAwICogbmNoYXJfc2NhbGVkICogKC0xKV5yb3dpZCwNCiAgICAgICAgIHBvaW50X3Bvc2l0aW9uID0gYyg1MCwxMDAsMjgwLDQyMCw1NTAsNzIwLDEwMCw1NTAsNzIwLDE1MCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAyNDAsNzgwLDgzMCwzMDApKigtMSlecm93aWQNCiAgICAgICAgICkgJT4lIA0KICBtdXRhdGUoZmFjZXRfdmFyID0gcXVhcnRlcihkYXRlLCB3aXRoX3llYXIgPSBUKSkgJT4lIA0KICANCiAgZ2dwbG90KGFlcyh4PWRhdGUsIHk9MCkpICsgDQogIGdlb21fbGluZSgpICsgDQogIGdlb21fcG9pbnQoYWVzKGNvbD1yZWdpb24pKSArDQogIGdlb21fc2VnbWVudChhZXMoeD1kYXRlLCB4ZW5kPWRhdGUsIGNvbD1yZWdpb24sDQogICAgICAgICAgICAgICAgICAgeT0wLCB5ZW5kPXBvaW50X3Bvc2l0aW9uKSkgKw0KICBnZW9tX3BvaW50KGFlcyh5PXBvaW50X3Bvc2l0aW9uLCBjb2w9cmVnaW9uKSwgc2hhcGU9MSkgKw0KICBnZW9tX3RleHQoYWVzKHk9LTEwLCANCiAgICAgICAgICAgICAgICBsYWJlbD1wYXN0ZTAoZGF5KGRhdGUpLCAiICIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb250aChkYXRlLCBsYWJlbD1UKSkpLCANCiAgICAgICAgICAgIGFuZ2xlPTMwLCANCiAgICAgICAgICAgIHZqdXN0PTEsIGhqdXN0PTEpICsgDQogIGdlb21fbGFiZWwoYWVzKGxhYmVsPXN0cl93cmFwKHBhc3RlMChkYXRlLCAiOiAiLCBldmVudCksIG5jaGFyLzMpLCBhbHBoYT0uNywNCiAgICAgICAgICAgICAgICAgIyBkaXJlY3Rpb25zPSJ5IiwgbWluLnNlZ21lbnQubGVuZ3RoID0gSW5mLA0KICAgICAgICAgICAgICAgICB4PWRhdGUsIHk9cG9pbnRfcG9zaXRpb24sIGNvbD1yZWdpb24sIHZqdXN0PSJvdXR3YXJkIikpICsNCiAgc2NhbGVfeF9kYXRlKGRhdGVfYnJlYWtzID0gIjEgbW9udGgiLCANCiAgICAgICAgICAgICAgIGRhdGVfbGFiZWxzID0gIiViICVZIikgKyANCiAgIyBmYWNldF93cmFwKH5mYWNldF92YXIsIHN0cmlwLnBvc2l0aW9uPSJ0b3AiLA0KICAjICAgICAgICAgICAgbmNvbCA9IDEsIHNjYWxlcyA9ICJmcmVlX3giKSArDQogICMgY29vcmRfZmxpcCgpICsNCiAgeWxpbSgtMTIwMCwxMjAwKSArIA0KICBjb29yZF9jYXJ0ZXNpYW4oY2xpcCA9ICJvZmYiKSArIA0KICBsYWJzKHN1YnRpdGxlID0gIkFVL05TVyBDb3ZpZC0xOSB0aW1lbGluZSwgMm5kIGhhbGYgMjAyMCIpICsNCiAgdGhlbWVfdm9pZChiYXNlX3NpemUgPSAyMykgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsIA0KICAgICAgICAjIHJlY3QgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIpLA0KICAgICAgICBwbG90Lm1hcmdpbiA9IHVuaXQoYygwLCAyLjMsIDAsIDIuMyksImNtIiksDQogICAgICAgICMgcGxvdC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSBOVUxMKQ0KICAgICAgICApDQpgYGANCg0KIyMgRnVsbA0KDQpgYGB7ciwgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTI1fQ0KQVVfdGltZWxpbmUgJT4lIA0KICAjIGZpbHRlcihkYXRlID49IHltZCgyMDIwMDIyMCkpICU+JSANCiAgYXJyYW5nZShkYXRlKSAlPiUgDQogIGFkZF9yb3coZGF0ZSA9IHltZCgyMDIwMDEyMCksIGV2ZW50PSIiKSAlPiUNCiAgIyBhZGRfcm93KGRhdGUgPSB5bWQoMjAyMDAyMjApLCBldmVudD0iIikgJT4lDQogIGFkZF9yb3coZGF0ZSA9IHltZCgyMDIwMDMzMSksIGV2ZW50PSIiKSAlPiUNCiAgYWRkX3JvdyhkYXRlID0geW1kKDIwMjAwNDAxKSwgZXZlbnQ9IiIpICU+JQ0KICBhZGRfcm93KGRhdGUgPSB5bWQoMjAyMDA2MzApLCBldmVudD0iIikgJT4lDQogIGFkZF9yb3coZGF0ZSA9IHltZCgyMDIwMDcwMSksIGV2ZW50PSIiKSAlPiUNCiAgYWRkX3JvdyhkYXRlID0geW1kKDIwMjAwOTMwKSwgZXZlbnQ9IiIpICU+JQ0KICBhZGRfcm93KGRhdGUgPSB5bWQoMjAyMDEwMDEpLCBldmVudD0iIikgJT4lDQogICMgZmlsdGVyKG5jaGFyKGV2ZW50KSA8IDIzMCkgJT4lIA0KICAjIGZpbHRlcihyZWdpb24gIT0gIlZJQyIpICU+JSANCiAgbXV0YXRlKHJvd2lkID0gYXMubnVtZXJpYyhyb3duYW1lcyguKSkpICU+JSANCiAgbXV0YXRlKGRhdGVfZ2FwID0gYXMubnVtZXJpYyhkYXRlLWxhZyhkYXRlKSkpICU+JSANCiAgbXV0YXRlKG5jaGFyID0gbmNoYXIoZXZlbnQpLCANCiAgICAgICAgIG5jaGFyX3NjYWxlZCA9IChuY2hhci1taW4obmNoYXIpKS8obWF4KG5jaGFyKS1taW4obmNoYXIpKSwgDQogICAgICAgICBwb2ludF9wb3NpdGlvbiA9IDgwMCAqIG5jaGFyX3NjYWxlZCAqICgtMSlecm93aWQsDQogICAgICAgICAjIHBvaW50X3Bvc2l0aW9uID0gYygxMDApKigtMSlecm93aWQNCiAgICAgICAgICkgJT4lIA0KICBtdXRhdGUoZmFjZXRfdmFyID0gcXVhcnRlcihkYXRlLCB3aXRoX3llYXIgPSBUKSkgJT4lIA0KICANCiAgZ2dwbG90KGFlcyh4PWRhdGUsIHk9MCkpICsgDQogIGdlb21fbGluZSgpICsgDQogIGdlb21fcG9pbnQoYWVzKGNvbD1yZWdpb24pKSArDQogIGdlb21fc2VnbWVudChhZXMoeD1kYXRlLCB4ZW5kPWRhdGUsIGNvbD1yZWdpb24sDQogICAgICAgICAgICAgICAgICAgeT0wLCB5ZW5kPXBvaW50X3Bvc2l0aW9uKSkgKw0KICBnZW9tX3BvaW50KGFlcyh5PXBvaW50X3Bvc2l0aW9uLCBjb2w9cmVnaW9uKSwgc2hhcGU9MSkgKw0KICBnZW9tX3RleHQoYWVzKHk9LTEwLCANCiAgICAgICAgICAgICAgICBsYWJlbD1wYXN0ZTAoZGF5KGRhdGUpLCAiICIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb250aChkYXRlLCBsYWJlbD1UKSkpLCANCiAgICAgICAgICAgIGFuZ2xlPTMwLCANCiAgICAgICAgICAgIHZqdXN0PTEsIGhqdXN0PTEpICsgDQogIGdlb21fbGFiZWwoYWVzKGxhYmVsPXN0cl93cmFwKHBhc3RlMChkYXRlLCAiOiAiLCBldmVudCksIG5jaGFyLzIpLCBhbHBoYT0uNywNCiAgICAgICAgICAgICAgICAgIyBkaXJlY3Rpb25zPSJ5IiwgbWluLnNlZ21lbnQubGVuZ3RoID0gSW5mLA0KICAgICAgICAgICAgICAgICB4PWRhdGUsIHk9cG9pbnRfcG9zaXRpb24sIGNvbD1yZWdpb24sIHZqdXN0PSJvdXR3YXJkIikpICsNCiAgc2NhbGVfeF9kYXRlKGRhdGVfYnJlYWtzID0gIjEgbW9udGgiLCANCiAgICAgICAgICAgICAgIGRhdGVfbGFiZWxzID0gIiViICVZIikgKyANCiAgZmFjZXRfd3JhcCh+ZmFjZXRfdmFyLCBzdHJpcC5wb3NpdGlvbj0idG9wIiwNCiAgICAgICAgICAgICBuY29sID0gMSwgc2NhbGVzID0gImZyZWVfeCIpICsNCiAgIyBjb29yZF9mbGlwKCkgKw0KICB5bGltKC0xMjAwLDEyMDApICsgDQogIGNvb3JkX2NhcnRlc2lhbihjbGlwID0gIm9mZiIpICsgDQogIHRoZW1lX3ZvaWQoYmFzZV9zaXplID0gMjMpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLCANCiAgICAgICAgIyByZWN0ID0gZWxlbWVudF9yZWN0KGZpbGwgPSAidHJhbnNwYXJlbnQiKSwNCiAgICAgICAgcGxvdC5tYXJnaW4gPSB1bml0KGMoMCwgMi4zLCAwLCAyLjMpLCJjbSIpLA0KICAgICAgICAjIHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gTlVMTCkNCiAgICAgICAgKQ0KYGBgDQoNCiMgVGltZSBzZXJpZXMNCiMjIERhaWx5DQoNCmBgYHtyLCBmaWcud2lkdGg9OCwgZmlnLmhlaWdodD00fQ0KY29uZmlybWVkX2Nhc2VzICU+JSANCiAgZmlsdGVyKGFzLmNoYXJhY3Rlcihwb3N0Y29kZSkgJWluJSBTWURfUE9BJFBPQV9OQU1FMTYpICU+JSANCiAgY291bnQobm90aWZpY2F0aW9uX2RhdGUpICU+JSANCiAgZ2dwbG90KGFlcyh4PW5vdGlmaWNhdGlvbl9kYXRlICwgeT1uKSkgKyANCiAgIyBnZW9tX3BvaW50KCkgKyANCiAgZ2VvbV9saW5lKCkgKyANCiAgeWxhYigiQ291bnQgb2YgY2FzZXMiKSArIA0KICBsYWJzKHN1YnRpdGxlID0gIkRhaWx5IG5ldyBjb25maXJtZWQgQ292aWQtMTkgY2FzZXMgKFNZRCkiKSArIA0KICBhbm5vdGF0ZSgidGV4dCIsIHg9eW1kKDIwMjAwNTA1KSwgeT02MCwgc2l6ZT0zLjMsIGNvbD0iZGFya3JlZCIsIA0KICAgICAgICAgICBsYWJlbD0iMXN0IG91dGJyZWFrIFxuIChCb25kaSBiZWFjaCwgXG5Tb3V0aCBFYXN0ZXJuIFxuU3lkbmV5KSIpICsgDQogIGFubm90YXRlKCJ0ZXh0IiwgeD15bWQoMjAyMDA4MTUpLCB5PTI1LCBzaXplPTMuMywgY29sPSJkYXJrcmVkIiwgDQogICAgICAgICAgIGxhYmVsPSIybmQgb3V0YnJlYWsgXG4gKFdlc3RtZWFkICYgTGl2ZXJwb29sLCBcbldlc3Rlcm4gU3lkbmV5KSIpICsgDQogIGFubm90YXRlKCJ0ZXh0IiwgeD15bWQoMjAyMTAxMDEpLCB5PTM1LCBzaXplPTMuMywgY29sPSJkYXJrcmVkIiwgDQogICAgICAgICAgIGxhYmVsPSIzcmQgb3V0YnJlYWsgXG4gKEF2YWxvbiBiZWFjaCwgTm9ydGhlcm4gU3lkbmV5KSIpICsgDQogIGdnbCgpDQpgYGANCg0KYGBge3IsIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTV9DQpjb25maXJtZWRfY2FzZXMgJT4lIA0KICBmaWx0ZXIoYXMuY2hhcmFjdGVyKHBvc3Rjb2RlKSAlaW4lIFNZRF9QT0EkUE9BX05BTUUxNikgJT4lIA0KICBjb3VudChsaGRfMjAxMF9uYW1lLCBub3RpZmljYXRpb25fZGF0ZSkgJT4lIA0KICBnZ3Bsb3QoYWVzKHg9bm90aWZpY2F0aW9uX2RhdGUgLCB5PW4sIGNvbD1saGRfMjAxMF9uYW1lKSkgKyANCiAgIyBnZW9tX3BvaW50KCkgKyANCiAgZ2VvbV9saW5lKCkgKyANCiAgIyBmYWNldF93cmFwKH5saGRfMjAxMF9uYW1lKSArIA0KICBsYWJzKHN1YnRpdGxlID0gIkRhaWx5IG5ldyBjb25maXJtZWQgQ292aWQtMTkgY2FzZXMgKFNZRCkiKSArIA0KICBnZ2wobHAgPSAicmlnaHQiKQ0KYGBgDQoNCiMjIEN1bXVsYXRpdmUNCg0KYGBge3IsIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTV9DQpjb25maXJtZWRfY2FzZXMgJT4lIA0KICBmaWx0ZXIoYXMuY2hhcmFjdGVyKHBvc3Rjb2RlKSAlaW4lIFNZRF9QT0EkUE9BX05BTUUxNikgJT4lIA0KICBtdXRhdGUobGhkXzIwMTBfbmFtZSA9IGlmZWxzZShsaGRfMjAxMF9uYW1lID09ICJTeWRuZXkiLCAiU3lkbmV5IChhcm91bmQgQ0JEKSIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsaGRfMjAxMF9uYW1lKSkgJT4lIA0KICAjIG11dGF0ZShsaGRfMjAxMF9uYW1lID0gaWZlbHNlKGlzLm5hKGxoZF8yMDEwX25hbWUpLCAiVW5rbm93biIsIGxoZF8yMDEwX25hbWUpKSAlPiUNCiAgY291bnQobGhkXzIwMTBfbmFtZSwgbm90aWZpY2F0aW9uX2RhdGUpICU+JSANCiAgZ3JvdXBfYnkobGhkXzIwMTBfbmFtZSkgJT4lIA0KICBtdXRhdGUoZGF5c19zaW5jZV9maXJzdF9jYXNlID0gbm90aWZpY2F0aW9uX2RhdGUgLSBtaW4obm90aWZpY2F0aW9uX2RhdGUpKSAlPiUgDQogIG11dGF0ZShhY2N1bXVsYXRlZF9jYXNlcyA9IGN1bXN1bShuKSkgJT4lIA0KICBtdXRhdGUobGFiID0gaWZlbHNlKG5vdGlmaWNhdGlvbl9kYXRlID09IG1heChub3RpZmljYXRpb25fZGF0ZSwgbmEucm09VCksIA0KICAgICAgICAgICAgICAgICAgICAgIGxoZF8yMDEwX25hbWUsIE5BKSkgJT4lIA0KICANCiAgZ2dwbG90KGFlcyh4PW5vdGlmaWNhdGlvbl9kYXRlICwgeT1hY2N1bXVsYXRlZF9jYXNlcywgY29sPWxoZF8yMDEwX25hbWUpKSArIA0KICAjIGdlb21fcG9pbnQoKSArIA0KICBnZW9tX2xpbmUoKSArIA0KICBnZW9tX3RleHRfcmVwZWwoYWVzKGxhYmVsPWxhYiksIHNpemU9NCwgaGp1c3Q9LS4xLCBtaW4uc2VnbWVudC5sZW5ndGggPSAxMCkgKyANCiAgIyBmYWNldF93cmFwKH5saGRfMjAxMF9uYW1lKSArIA0KICBsYWJzKHN1YnRpdGxlID0gIkFjY3VtdWxhdGVkIGNvbmZpcm1lZCBDb3ZpZC0xOSBjYXNlcyAoU1lEKSwgYnkgcmVnaW9uIikgKyANCiAgIyB4bGltKGMoMCw1NTApKSArDQogIGdnbChscCA9ICJub25lIikgDQpgYGANCg0KYGBge3IsIGZpZy53aWR0aD05LCBmaWcuaGVpZ2h0PTZ9DQpjb25maXJtZWRfY2FzZXMgJT4lIA0KICBtdXRhdGUobGhkXzIwMTBfbmFtZSA9IGlmZWxzZShsaGRfMjAxMF9uYW1lID09ICJTeWRuZXkiLCAiTWV0cm8gU3lkbmV5IiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxoZF8yMDEwX25hbWUpKSAlPiUgDQogIGZpbHRlcihhcy5jaGFyYWN0ZXIocG9zdGNvZGUpICVpbiUgU1lEX1BPQSRQT0FfTkFNRTE2KSAlPiUgDQogICMgZmlsdGVyKGxoZF8yMDEwX25hbWUgJWluJSBjKCJTb3V0aCBFYXN0ZXJuIFN5ZG5leSIsIA0KICAjICAgICAgICAgICAgICAgICAgICAgICAgICAiTm9ydGhlcm4gU3lkbmV5IiwgDQogICMgICAgICAgICAgICAgICAgICAgICAgICAgICJXZXN0ZXJuIFN5ZG5leSIsIA0KICAjICAgICAgICAgICAgICAgICAgICAgICAgICAiU291dGggV2VzdGVybiBTeWRuZXkiLCANCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgIlN5ZG5leSIpIHwgaXMubmEobGhkXzIwMTBfbmFtZSkpICU+JSANCiAgY291bnQobGhkXzIwMTBfbmFtZSwgcG9zdGNvZGUsIG5vdGlmaWNhdGlvbl9kYXRlKSAlPiUgDQogIGdyb3VwX2J5KGxoZF8yMDEwX25hbWUsIHBvc3Rjb2RlKSAlPiUgDQogIG11dGF0ZShkYXlzX3NpbmNlX2ZpcnN0X2Nhc2UgPSBub3RpZmljYXRpb25fZGF0ZSAtIG1pbihub3RpZmljYXRpb25fZGF0ZSkpICU+JSANCiAgbXV0YXRlKGFjY3VtdWxhdGVkX2Nhc2VzID0gY3Vtc3VtKG4pKSAlPiUgDQogIG11dGF0ZShsYWI9aWZlbHNlKG5vdGlmaWNhdGlvbl9kYXRlID09IG1heChub3RpZmljYXRpb25fZGF0ZSksIHBvc3Rjb2RlLCBOQSkpICU+JSANCiAgDQogIGdncGxvdChhZXMoeD1ub3RpZmljYXRpb25fZGF0ZSAsIHk9YWNjdW11bGF0ZWRfY2FzZXMsIA0KICAgICAgICAgICAgIGdyb3VwPXBvc3Rjb2RlLA0KICAgICAgICAgICAgIGNvbD1saGRfMjAxMF9uYW1lKSkgKyANCiAgIyBnZW9tX3BvaW50KCkgKyANCiAgZ2VvbV9saW5lKCkgKyANCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbD1sYWIpLCBzaXplPTMsIGhqdXN0PSJvdXR3YXJkIikgKyANCiAgZmFjZXRfd3JhcCh+bGhkXzIwMTBfbmFtZSkgKw0KICBsYWJzKHN1YnRpdGxlID0gIkFjY3VtdWxhdGVkIGNvbmZpcm1lZCBDb3ZpZC0xOSBjYXNlcyAoU1lEKSwgYnkgcG9zdGNvZGUiKSArIA0KICAjIHhsaW0oYygwLDU1MCkpICsNCiAgZ2dsKGxwID0gIm5vbmUiLCApICsgDQogIHRoZW1lKHN0cmlwLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpKQ0KYGBgDQoNCiMgTWFwDQoNCkxvb2tzIGxpa2UgZWFjaCBwb3N0Y29kZSAoUE9BKSBjYW4gb25seSBiZWxvbmcgdG8gb25lIExHQSwgd2hpY2ggaXMgbm90IHRoZSBjYXNlIGZvciBTQTINCg0KYGBge3J9DQpjb25maXJtZWRfY2FzZXMgJT4lIA0KICBkaXN0aW5jdChwb3N0Y29kZSwgbGdhX25hbWUxOSkgJT4lIA0KICBjb3VudChwb3N0Y29kZSkgJT4lIA0KICBzdW1tYXJpc2UobWF4KG4pKSAlPiUgDQogIHB1bGwoKQ0KYGBgDQoNCg0KIyMgTEdBDQoNCmBgYHtyLCBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9N30NCmNvbmZpcm1lZF9jYXNlcyAlPiUgDQogIGZpbHRlcihsZ2FfbmFtZTE5ICVpbiUgU1lEX0xHQSRMR0FfTkFNRTE5KSAlPiUgDQogIGNvdW50KGxnYV9uYW1lMTksIG5hbWU9IlRvdGFsX2Nhc2VzIikgJT4lIA0KICByZW5hbWUoTEdBX05BTUUxOSA9IGxnYV9uYW1lMTkpICU+JSANCiAgbXV0YXRlKExHQV9OQU1FMTkgPSBmY3RfcmVvcmRlcihMR0FfTkFNRTE5LCBUb3RhbF9jYXNlcykpICU+JSANCiAgcGxvdF9tYXBfVEwoU1lEX0xHQSwgIkxHQV9OQU1FMTkiLCAiVG90YWxfY2FzZXMiLCANCiAgICAgICAgICAgIlRvdGFsIENvdmlkLTE5IGNhc2VzIGJ5IExHQSAoU1lEKSIsIHNob3dfY291bnQgPSBUKQ0KYGBgDQoNCiMjIFBPQQ0KDQpgYGB7ciwgZmlnLndpZHRoPTkuNSwgZmlnLmhlaWdodD03fQ0KY29uZmlybWVkX2Nhc2VzICU+JSANCiAgZmlsdGVyKGFzLmNoYXJhY3Rlcihwb3N0Y29kZSkgJWluJSBTWURfUE9BJFBPQV9OQU1FMTYpICU+JSANCiAgY291bnQocG9zdGNvZGUsIG5hbWU9IlRvdGFsX2Nhc2VzIikgJT4lIA0KICByZW5hbWUoUE9BX05BTUUxNiA9IHBvc3Rjb2RlKSAlPiUgDQogIG11dGF0ZShQT0FfTkFNRTE2ID0gZmN0X3Jlb3JkZXIoYXMuZmFjdG9yKFBPQV9OQU1FMTYpLCBUb3RhbF9jYXNlcykpICU+JSANCiAgcGxvdF9tYXBfVEwoU1lEX1BPQSwgIlBPQV9OQU1FMTYiLCAiVG90YWxfY2FzZXMiLCANCiAgICAgICAgICAgIlRvdGFsIENvdmlkLTE5IGNhc2VzIGJ5IFBPQSAoU1lEKSIsIA0KICAgICAgICAgICBzaG93X2NvdW50ID0gVCwgbGFiZWxfc2l6ZSA9IDIpDQpgYGANCg0KYGBge3IsIGZpZy53aWR0aD05LjUsIGZpZy5oZWlnaHQ9N30NCmNvbmZpcm1lZF9jYXNlcyAlPiUNCiAgZmlsdGVyKGFzLmNoYXJhY3Rlcihwb3N0Y29kZSkgJWluJSBTWURfUE9BJFBPQV9OQU1FMTYpICU+JQ0KICBjb3VudChwb3N0Y29kZSwgbmFtZT0iVG90YWxfY2FzZXMiKSAlPiUNCiAgcmVuYW1lKFBPQV9OQU1FMTYgPSBwb3N0Y29kZSkgJT4lDQogIG11dGF0ZShQT0FfTkFNRTE2ID0gZmN0X3Jlb3JkZXIoYXMuZmFjdG9yKFBPQV9OQU1FMTYpLCBUb3RhbF9jYXNlcykpICU+JQ0KICBtdXRhdGUoY2x1c3Rlcl9vcmlnaW4gPSBpZmVsc2UoUE9BX05BTUUxNiAlaW4lIGMoIjIwMjYiLCAiMjE0NSIsICIyMTA3IiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiY2x1c3Rlcl9vcmlnaW4iLCAiIikgJT4lIGFzLmZhY3RvcikgJT4lDQogIHBsb3RfbWFwX2ZhY3Rvcl9UTChTWURfUE9BLCAiUE9BX05BTUUxNiIsICJUb3RhbF9jYXNlcyIsICJjbHVzdGVyX29yaWdpbiIsDQogICAgICAgICAgICAgICJUb3RhbCBDb3ZpZC0xOSBjYXNlcyBieSBQT0EgKFNZRCksIGhpZ2hsaWdodGVkIGJ5IGNsdXN0ZXIgb3JpZ2luIiwNCiAgICAgICAgICAgICAgc2hvd19jb3VudCA9IFQsIGxhYmVsX3NpemUgPSAyKQ0KYGBgDQoNCmBgYHtyLCBmaWcud2lkdGg9OS41LCBmaWcuaGVpZ2h0PTd9DQpjb25maXJtZWRfY2FzZXMgJT4lIA0KICBmaWx0ZXIoIShwb3N0Y29kZSAlaW4lIGMoMjAyNiwgMjE0NSwgMjE3MCkpKSAlPiUgDQogIGZpbHRlcihhcy5jaGFyYWN0ZXIocG9zdGNvZGUpICVpbiUgU1lEX1BPQSRQT0FfTkFNRTE2KSAlPiUgDQogIGNvdW50KHBvc3Rjb2RlLCBuYW1lPSJUb3RhbF9jYXNlcyIpICU+JSANCiAgcmVuYW1lKFBPQV9OQU1FMTYgPSBwb3N0Y29kZSkgJT4lIA0KICBtdXRhdGUoUE9BX05BTUUxNiA9IGZjdF9yZW9yZGVyKGFzLmZhY3RvcihQT0FfTkFNRTE2KSwgVG90YWxfY2FzZXMpKSAlPiUgDQogIHBsb3RfbWFwX1RMKFNZRF9QT0EsICJQT0FfTkFNRTE2IiwgIlRvdGFsX2Nhc2VzIiwgDQogICAgICAgICAgICJUb3RhbCBDb3ZpZC0xOSBjYXNlcyBieSBQT0EgKFNZRCksIGV4Y2x1ZGluZyB0b3AgMyBQT0EiLCANCiAgICAgICAgICAgc2hvd19jb3VudCA9IFQsIGxhYmVsX3NpemUgPSAyKQ0KYGBgDQoNCiMjIE5vdGUNCg0KTm9ydGhlcm4gQmVhY2hlcyBoYXMgbWFueSBwb3N0Y29kZXMgd2hpY2ggcmVzdWx0IGluIG1vcmUgZGlsdXRlZCBjaG9yb3BsZXRoIGJ5IFBPQS4NCg0KYGBge3IsIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTZ9DQpjb25maXJtZWRfY2FzZXMgJT4lIA0KICBkaXN0aW5jdChsZ2FfbmFtZTE5LCBwb3N0Y29kZSkgJT4lIA0KICBjb3VudChsZ2FfbmFtZTE5LCBuYW1lPSJOdW1iZXJfb2ZfcG9zdGNvZGVzIikgJT4lIA0KICBsZWZ0X2pvaW4oY29uZmlybWVkX2Nhc2VzICU+JSBjb3VudChsZ2FfbmFtZTE5LCBuYW1lPSJUb3RhbF9jYXNlcyIpLCANCiAgICAgICAgICAgIGJ5PSJsZ2FfbmFtZTE5IikgJT4lIA0KICBzbGljZV9tYXgobj0zMCwgb3JkZXJfYnkgPSBUb3RhbF9jYXNlcykgJT4lIA0KICBnYXRoZXIoa2V5LCB2YWx1ZSwgLWxnYV9uYW1lMTkpICU+JSANCiAgZ2dwbG90KGFlcyh4PXJlb3JkZXIobGdhX25hbWUxOSwgdmFsdWUpLCB5PXZhbHVlKSkgKyANCiAgZ2VvbV9jb2woKSArIA0KICBmYWNldF93cmFwKH5rZXksIHNjYWxlcyA9ICJmcmVlX3giKSArIA0KICBjb29yZF9mbGlwKCkgKyANCiAgeGxhYigiIikgKyB5bGFiKCIiKSArIA0KICBnZ2woKQ0KYGBgDQoNCiMgTWFwIG92ZXJ0aW1lIGN1bXVsYXRpdmUNCiMjIEJ5IHF1YXJ0ZXIgey50YWJzZXR9DQojIyMgQWNjdW11bGF0ZWQgY2FzZXMNCg0KYGBge3IsIGZpZy53aWR0aD05LjUsIGZpZy5oZWlnaHQ9N30NCmNvbmZpcm1lZF9jYXNlcyAlPiUgDQogIGZpbHRlcihhcy5jaGFyYWN0ZXIocG9zdGNvZGUpICVpbiUgU1lEX1BPQSRQT0FfTkFNRTE2KSAlPiUgDQogIG11dGF0ZSh5ZWFyX3F1YXJ0ZXIgPSBwYXN0ZSh5ZWFyKG5vdGlmaWNhdGlvbl9kYXRlKSwgIlEiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBxdWFydGVyKG5vdGlmaWNhdGlvbl9kYXRlKSwgc2VwPSItIikpICU+JSANCiAgY291bnQoeWVhcl9xdWFydGVyLCBwb3N0Y29kZSwgbmFtZT0iVG90YWxfY2FzZXMiKSAlPiUgDQogIGNvbXBsZXRlKHllYXJfcXVhcnRlciwgcG9zdGNvZGUsIGZpbGwgPSBsaXN0KFRvdGFsX2Nhc2VzPTApKSAlPiUgDQogIGdyb3VwX2J5KHBvc3Rjb2RlKSAlPiUgDQogIG11dGF0ZShBY2N1bXVsYXRlZF9jYXNlcyA9IGN1bXN1bShUb3RhbF9jYXNlcykpICU+JSANCiAgZ3JvdXBfYnkoeWVhcl9xdWFydGVyKSAlPiUgDQogIG11dGF0ZShBY2N1bXVsYXRlZF9zaGFyZSA9IChBY2N1bXVsYXRlZF9jYXNlcy9zdW0oQWNjdW11bGF0ZWRfY2FzZXMsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hLnJtPVQpKSkgJT4lIA0KICBtdXRhdGUoZmFjZXRfdmFyID0gcGFzdGUwKHllYXJfcXVhcnRlciwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIlxuQWNjdW11bGF0ZWQ6ICIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbW1hKHN1bShBY2N1bXVsYXRlZF9jYXNlcykpKSkgJT4lIA0KICByZW5hbWUoUE9BX05BTUUxNiA9IHBvc3Rjb2RlKSAlPiUgDQogIA0KICBwbG90X21hcF9UTChybWFwc2hhcGVyOjptc19zaW1wbGlmeSgNCiAgICBTWURfUE9BW1NZRF9QT0EkUE9BX05BTUUxNiAlaW4lIGFzLmNoYXJhY3RlcigNCiAgICAgIGNvbmZpcm1lZF9jYXNlcyRwb3N0Y29kZSkgLF0sIC4wMSksIA0KICAgICAgICAgICAgICAiUE9BX05BTUUxNiIsICJBY2N1bXVsYXRlZF9jYXNlcyIsIA0KICAgICAgICAgICAiVG90YWwgYWNjdW11bGF0ZWQgQ292aWQtMTkgY2FzZXMgYnkgUE9BIChTWUQpLCBvdmVydGltZSIsIA0KICAgICAgICAgICByZXR1cm5fb2JqPSJtYXAiKSArIA0KICBmYWNldF93cmFwKH5mYWNldF92YXIpICsgDQogIHRoZW1lX21hcF9mYWNldF9UTA0KYGBgDQoNCiMjIyBBY2N1bXVsYXRlZCBzaGFyZQ0KDQpgYGB7ciwgZmlnLndpZHRoPTkuNSwgZmlnLmhlaWdodD03fQ0KY29uZmlybWVkX2Nhc2VzICU+JSANCiAgZmlsdGVyKGFzLmNoYXJhY3Rlcihwb3N0Y29kZSkgJWluJSBTWURfUE9BJFBPQV9OQU1FMTYpICU+JSANCiAgbXV0YXRlKHllYXJfcXVhcnRlciA9IHBhc3RlKHllYXIobm90aWZpY2F0aW9uX2RhdGUpLCAiUSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHF1YXJ0ZXIobm90aWZpY2F0aW9uX2RhdGUpLCBzZXA9Ii0iKSkgJT4lIA0KICBjb3VudCh5ZWFyX3F1YXJ0ZXIsIHBvc3Rjb2RlLCBuYW1lPSJUb3RhbF9jYXNlcyIpICU+JSANCiAgY29tcGxldGUoeWVhcl9xdWFydGVyLCBwb3N0Y29kZSwgZmlsbCA9IGxpc3QoVG90YWxfY2FzZXM9MCkpICU+JSANCiAgZ3JvdXBfYnkocG9zdGNvZGUpICU+JSANCiAgbXV0YXRlKEFjY3VtdWxhdGVkX2Nhc2VzID0gY3Vtc3VtKFRvdGFsX2Nhc2VzKSkgJT4lIA0KICBncm91cF9ieSh5ZWFyX3F1YXJ0ZXIpICU+JSANCiAgbXV0YXRlKEFjY3VtdWxhdGVkX3NoYXJlID0gKEFjY3VtdWxhdGVkX2Nhc2VzL3N1bShBY2N1bXVsYXRlZF9jYXNlcywgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmEucm09VCkpKSAlPiUNCiAgbXV0YXRlKGZhY2V0X3ZhciA9IHBhc3RlMCh5ZWFyX3F1YXJ0ZXIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICJcbkFjY3VtdWxhdGVkOiAiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb21tYShzdW0oQWNjdW11bGF0ZWRfY2FzZXMpKSkpICU+JSANCiAgcmVuYW1lKFBPQV9OQU1FMTYgPSBwb3N0Y29kZSkgJT4lIA0KICANCiAgcGxvdF9tYXBfVEwocm1hcHNoYXBlcjo6bXNfc2ltcGxpZnkoDQogICAgU1lEX1BPQVtTWURfUE9BJFBPQV9OQU1FMTYgJWluJSBhcy5jaGFyYWN0ZXIoDQogICAgICBjb25maXJtZWRfY2FzZXMkcG9zdGNvZGUpICxdLCAuMDEpLCANCiAgICAgICAgICAgICAgIlBPQV9OQU1FMTYiLCAiQWNjdW11bGF0ZWRfc2hhcmUiLCANCiAgICAgICAgICAgIlRvdGFsIENvdmlkLTE5IGNhc2VzIGJ5IFBPQSAoU1lEKSIsIA0KICAgICAgICAgICByZXR1cm5fb2JqPSJtYXAiKSArIA0KICBmYWNldF93cmFwKH5mYWNldF92YXIpICsgDQogIHRoZW1lX21hcF9mYWNldF9UTA0KYGBgDQoNCiMjIEJ5IHdlZWsgTWFyLU1heSAyMDIwIHsudGFic2V0fQ0KIyMjIEFjY3VtdWxhdGVkIGNhc2VzDQoNCmBgYHtyLCBmaWcud2lkdGg9OS41LCBmaWcuaGVpZ2h0PTEwfQ0KY29uZmlybWVkX2Nhc2VzICU+JSANCiAgZmlsdGVyKGFzLmNoYXJhY3Rlcihwb3N0Y29kZSkgJWluJSBTWURfUE9BJFBPQV9OQU1FMTYpICU+JSANCiAgZmlsdGVyKHllYXIobm90aWZpY2F0aW9uX2RhdGUpID09IDIwMjAsIA0KICAgICAgICAgIyBtb250aChub3RpZmljYXRpb25fZGF0ZSkgJWluJSAzOjUsIA0KICAgICAgICAgaXNvd2Vlayhub3RpZmljYXRpb25fZGF0ZSkgJWluJSAxMDoyMykgJT4lIA0KICBmaWx0ZXIoYXMuY2hhcmFjdGVyKHBvc3Rjb2RlKSAlaW4lIFNZRF9QT0EkUE9BX05BTUUxNikgJT4lIA0KICBtdXRhdGUoaXNvd2VlayA9IGlzb3dlZWsobm90aWZpY2F0aW9uX2RhdGUpKSAlPiUgDQogIGNvdW50KGlzb3dlZWssIHBvc3Rjb2RlLCBuYW1lPSJUb3RhbF9jYXNlcyIpICU+JSANCiAgY29tcGxldGUoaXNvd2VlaywgcG9zdGNvZGUsIGZpbGwgPSBsaXN0KFRvdGFsX2Nhc2VzPTApKSAlPiUgDQogIGdyb3VwX2J5KHBvc3Rjb2RlKSAlPiUgDQogIG11dGF0ZShBY2N1bXVsYXRlZF9jYXNlcyA9IGN1bXN1bShUb3RhbF9jYXNlcykpICU+JSANCiAgZ3JvdXBfYnkoaXNvd2VlaykgJT4lIA0KICBtdXRhdGUoQWNjdW11bGF0ZWRfc2hhcmUgPSAoQWNjdW11bGF0ZWRfY2FzZXMvc3VtKEFjY3VtdWxhdGVkX2Nhc2VzLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYS5ybT1UKSkpICU+JQ0KICBtdXRhdGUoZmFjZXRfdmFyID0gcGFzdGUwKCJ3ZWVrICIsIGlzb3dlZWssIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICJcbkFjY3VtdWxhdGVkOiAiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb21tYShzdW0oQWNjdW11bGF0ZWRfY2FzZXMpKSkpICU+JSANCiAgcmVuYW1lKFBPQV9OQU1FMTYgPSBwb3N0Y29kZSkgJT4lIA0KICBtdXRhdGUoUE9BX05BTUUxNiA9IGZjdF9yZW9yZGVyKGFzLmZhY3RvcihQT0FfTkFNRTE2KSwgVG90YWxfY2FzZXMpKSAlPiUgDQogIHVuZ3JvdXAoKSAlPiUgDQogIGZpbHRlcighaXMubmEoaXNvd2VlaykpICU+JSANCiAgDQogIHBsb3RfbWFwX1RMKHJtYXBzaGFwZXI6Om1zX3NpbXBsaWZ5KFNZRF9QT0EsIC4wMSksIA0KICAgICAgICAgICAgICAiUE9BX05BTUUxNiIsICJBY2N1bXVsYXRlZF9jYXNlcyIsIA0KICAgICAgICAgICAgICAiVG90YWwgQ292aWQtMTkgY2FzZXMgYnkgUE9BIChTWUQpIiwgDQogICAgICAgICAgICAgIHJldHVybl9vYmo9Im1hcCIpICsgDQogIGZhY2V0X3dyYXAofmZhY2V0X3ZhcikgKyANCiAgdGhlbWVfbWFwX2ZhY2V0X1RMICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gYyguODMsIC4xNSkpDQpgYGANCg0KIyMjIEFjY3VtdWxhdGVkIHNoYXJlDQoNCmBgYHtyLCBmaWcud2lkdGg9OS41LCBmaWcuaGVpZ2h0PTEwfQ0KY29uZmlybWVkX2Nhc2VzICU+JSANCiAgZmlsdGVyKGFzLmNoYXJhY3Rlcihwb3N0Y29kZSkgJWluJSBTWURfUE9BJFBPQV9OQU1FMTYpICU+JSANCiAgZmlsdGVyKHllYXIobm90aWZpY2F0aW9uX2RhdGUpID09IDIwMjAsIA0KICAgICAgICAgIyBtb250aChub3RpZmljYXRpb25fZGF0ZSkgJWluJSAzOjUsIA0KICAgICAgICAgaXNvd2Vlayhub3RpZmljYXRpb25fZGF0ZSkgJWluJSAxMDoyMykgJT4lIA0KICBmaWx0ZXIoYXMuY2hhcmFjdGVyKHBvc3Rjb2RlKSAlaW4lIFNZRF9QT0EkUE9BX05BTUUxNikgJT4lIA0KICBtdXRhdGUoaXNvd2VlayA9IGlzb3dlZWsobm90aWZpY2F0aW9uX2RhdGUpKSAlPiUgDQogIGNvdW50KGlzb3dlZWssIHBvc3Rjb2RlLCBuYW1lPSJUb3RhbF9jYXNlcyIpICU+JSANCiAgY29tcGxldGUoaXNvd2VlaywgcG9zdGNvZGUsIGZpbGwgPSBsaXN0KFRvdGFsX2Nhc2VzPTApKSAlPiUgDQogIGdyb3VwX2J5KHBvc3Rjb2RlKSAlPiUgDQogIG11dGF0ZShBY2N1bXVsYXRlZF9jYXNlcyA9IGN1bXN1bShUb3RhbF9jYXNlcykpICU+JSANCiAgZ3JvdXBfYnkoaXNvd2VlaykgJT4lIA0KICBtdXRhdGUoQWNjdW11bGF0ZWRfc2hhcmUgPSAoQWNjdW11bGF0ZWRfY2FzZXMvc3VtKEFjY3VtdWxhdGVkX2Nhc2VzLCBuYS5ybT1UKSkpICU+JSANCiAgcmVuYW1lKFBPQV9OQU1FMTYgPSBwb3N0Y29kZSkgJT4lIA0KICBtdXRhdGUoUE9BX05BTUUxNiA9IGZjdF9yZW9yZGVyKGFzLmZhY3RvcihQT0FfTkFNRTE2KSwgVG90YWxfY2FzZXMpKSAlPiUgDQogIG11dGF0ZShmYWNldF92YXIgPSBwYXN0ZTAoIndlZWsgIiwgaXNvd2VlaywgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIlxuQWNjdW11bGF0ZWQ6ICIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbW1hKHN1bShBY2N1bXVsYXRlZF9jYXNlcykpKSkgJT4lIA0KICB1bmdyb3VwKCkgJT4lIA0KICBmaWx0ZXIoIWlzLm5hKGlzb3dlZWspKSAlPiUgDQogIA0KICBwbG90X21hcF9UTChybWFwc2hhcGVyOjptc19zaW1wbGlmeShTWURfUE9BLCAuMDEpLCANCiAgICAgICAgICAgICAgIlBPQV9OQU1FMTYiLCAiQWNjdW11bGF0ZWRfc2hhcmUiLCANCiAgICAgICAgICAgICAgIlRvdGFsIENvdmlkLTE5IGNhc2VzIGJ5IFBPQSAoU1lEKSIsIA0KICAgICAgICAgICAgICByZXR1cm5fb2JqPSJtYXAiKSArIA0KICBmYWNldF93cmFwKH5mYWNldF92YXIpICsgDQogIHRoZW1lX21hcF9mYWNldF9UTCArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9IGMoLjgzLCAuMTUpKQ0KYGBgDQoNCiMgRGlzdHJpYnV0aW9uIG9mIHNoYXJlIG92ZXJ0aW1lDQojIyBCeSBxdWFydGVyDQoNCmBgYHtyLCBmaWcud2lkdGg9OCwgZmlnLmhlaWdodD0zLjN9DQpjb25maXJtZWRfY2FzZXMgJT4lIA0KICBmaWx0ZXIoYXMuY2hhcmFjdGVyKHBvc3Rjb2RlKSAlaW4lIFNZRF9QT0EkUE9BX05BTUUxNikgJT4lIA0KICBtdXRhdGUoeWVhcl9xdWFydGVyID0gcGFzdGUoeWVhcihub3RpZmljYXRpb25fZGF0ZSksICJRIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcXVhcnRlcihub3RpZmljYXRpb25fZGF0ZSksIHNlcD0iLSIpKSAlPiUgDQogIGNvdW50KHllYXJfcXVhcnRlciwgcG9zdGNvZGUsIG5hbWU9IlRvdGFsX2Nhc2VzIikgJT4lIA0KICBjb21wbGV0ZSh5ZWFyX3F1YXJ0ZXIsIHBvc3Rjb2RlLCBmaWxsID0gbGlzdChUb3RhbF9jYXNlcz0wKSkgJT4lIA0KICBncm91cF9ieShwb3N0Y29kZSkgJT4lIA0KICBtdXRhdGUoQWNjdW11bGF0ZWRfY2FzZXMgPSBjdW1zdW0oVG90YWxfY2FzZXMpKSAlPiUgDQogIHVuZ3JvdXAoKSAlPiUgDQogIGNvbXBsZXRlKHllYXJfcXVhcnRlciwgcG9zdGNvZGUpICU+JSANCiAgcmVwbGFjZV9uYShsaXN0KEFjY3VtdWxhdGVkX2Nhc2VzPTApKSAlPiUgDQogIGdyb3VwX2J5KHllYXJfcXVhcnRlcikgJT4lIA0KICBtdXRhdGUoQWNjdW11bGF0ZWRfc2hhcmUgPSAoQWNjdW11bGF0ZWRfY2FzZXMvc3VtKEFjY3VtdWxhdGVkX2Nhc2VzLCBuYS5ybT1UKSkpICU+JSANCiAgcmVuYW1lKFBPQV9OQU1FMTYgPSBwb3N0Y29kZSkgJT4lIA0KICB1bmdyb3VwKCkgJT4lIA0KICANCiAgZ2dwbG90KGFlcyh4PXllYXJfcXVhcnRlciwgeT1BY2N1bXVsYXRlZF9jYXNlcywgDQogICAgICAgICAgICAgZmlsbD1BY2N1bXVsYXRlZF9jYXNlcyA+IDUwLA0KICAgICAgICAgICAgIGdyb3VwPWFzLmZhY3RvcihQT0FfTkFNRTE2KSkpICsgDQogIGdlb21fY29sKGNvbD0id2hpdGUiLCBzaXplPS4xKSArIA0KICBnZ2YoZmMgPSBEQ1syOjFdKSArIA0KICBnZ2woInRvcCIsIGx0ID0gVCkNCmBgYA0KDQoNCmBgYHtyLCBmaWcud2lkdGg9OCwgZmlnLmhlaWdodD0yLjV9DQpjb25maXJtZWRfY2FzZXMgJT4lIA0KICBmaWx0ZXIoYXMuY2hhcmFjdGVyKHBvc3Rjb2RlKSAlaW4lIFNZRF9QT0EkUE9BX05BTUUxNikgJT4lIA0KICBtdXRhdGUoeWVhcl9xdWFydGVyID0gcGFzdGUoeWVhcihub3RpZmljYXRpb25fZGF0ZSksICJRIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcXVhcnRlcihub3RpZmljYXRpb25fZGF0ZSksIHNlcD0iLSIpKSAlPiUgDQogIGNvdW50KHllYXJfcXVhcnRlciwgcG9zdGNvZGUsIG5hbWU9IlRvdGFsX2Nhc2VzIikgJT4lIA0KICBncm91cF9ieShwb3N0Y29kZSkgJT4lIA0KICBtdXRhdGUoQWNjdW11bGF0ZWRfY2FzZXMgPSBjdW1zdW0oVG90YWxfY2FzZXMpKSAlPiUgDQogIHVuZ3JvdXAoKSAlPiUgDQogIGNvbXBsZXRlKHllYXJfcXVhcnRlciwgcG9zdGNvZGUpICU+JSANCiAgcmVwbGFjZV9uYShsaXN0KEFjY3VtdWxhdGVkX2Nhc2VzPTApKSAlPiUgDQogIGdyb3VwX2J5KHllYXJfcXVhcnRlcikgJT4lIA0KICBtdXRhdGUoQWNjdW11bGF0ZWRfc2hhcmUgPSAoQWNjdW11bGF0ZWRfY2FzZXMvc3VtKEFjY3VtdWxhdGVkX2Nhc2VzLCBuYS5ybT1UKSkpICU+JSANCiAgcmVuYW1lKFBPQV9OQU1FMTYgPSBwb3N0Y29kZSkgJT4lIA0KICANCiAgZ2dwbG90KGFlcyh4PUFjY3VtdWxhdGVkX3NoYXJlLCBmaWxsPWFzLmZhY3Rvcih5ZWFyX3F1YXJ0ZXIpKSkgKyANCiAgIyBnZW9tX2RlbnNpdHkoKSArIA0KICBnZW9tX2hpc3RvZ3JhbSgpICsgDQogIGZhY2V0X3dyYXAofnllYXJfcXVhcnRlciwgbnJvdyA9IDEpICsgDQogIHhsaW0oMCwuMDMpICsgDQogIHlsaW0oMCw0MCkgKw0KICBnZ2woIm5vbmUiKQ0KYGBgDQoNCiMjIEJ5IHdlZWsNCg0KYGBge3IsIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTMuM30NCmNvbmZpcm1lZF9jYXNlcyAlPiUgDQogIGZpbHRlcihhcy5jaGFyYWN0ZXIocG9zdGNvZGUpICVpbiUgU1lEX1BPQSRQT0FfTkFNRTE2KSAlPiUgDQogIGZpbHRlcih5ZWFyKG5vdGlmaWNhdGlvbl9kYXRlKSA9PSAyMDIwLCANCiAgICAgICAgICMgbW9udGgobm90aWZpY2F0aW9uX2RhdGUpICVpbiUgMzo1LCANCiAgICAgICAgIGlzb3dlZWsobm90aWZpY2F0aW9uX2RhdGUpICVpbiUgMTA6MjMpICU+JSANCiAgZmlsdGVyKGFzLmNoYXJhY3Rlcihwb3N0Y29kZSkgJWluJSBTWURfUE9BJFBPQV9OQU1FMTYpICU+JSANCiAgbXV0YXRlKGlzb3dlZWsgPSBpc293ZWVrKG5vdGlmaWNhdGlvbl9kYXRlKSkgJT4lIA0KICBjb3VudChpc293ZWVrLCBwb3N0Y29kZSwgbmFtZT0iVG90YWxfY2FzZXMiKSAlPiUgDQogIGNvbXBsZXRlKGlzb3dlZWssIHBvc3Rjb2RlLCBmaWxsID0gbGlzdChUb3RhbF9jYXNlcz0wKSkgJT4lIA0KICBncm91cF9ieShwb3N0Y29kZSkgJT4lIA0KICBtdXRhdGUoQWNjdW11bGF0ZWRfY2FzZXMgPSBjdW1zdW0oVG90YWxfY2FzZXMpKSAlPiUgDQogIGdyb3VwX2J5KGlzb3dlZWspICU+JSANCiAgbXV0YXRlKEFjY3VtdWxhdGVkX3NoYXJlID0gKEFjY3VtdWxhdGVkX2Nhc2VzL3N1bShBY2N1bXVsYXRlZF9jYXNlcywgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmEucm09VCkpKSAlPiUNCiAgbXV0YXRlKGZhY2V0X3ZhciA9IHBhc3RlMCgid2VlayAiLCBpc293ZWVrLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiXG5BY2N1bXVsYXRlZDogIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgY29tbWEoc3VtKEFjY3VtdWxhdGVkX2Nhc2VzKSkpKSAlPiUgDQogIHJlbmFtZShQT0FfTkFNRTE2ID0gcG9zdGNvZGUpICU+JSANCiAgbXV0YXRlKFBPQV9OQU1FMTYgPSBmY3RfcmVvcmRlcihhcy5mYWN0b3IoUE9BX05BTUUxNiksIFRvdGFsX2Nhc2VzKSkgJT4lIA0KICB1bmdyb3VwKCkgJT4lIA0KICBmaWx0ZXIoIWlzLm5hKGlzb3dlZWspKSAlPiUgDQogIA0KICBnZ3Bsb3QoYWVzKHg9aXNvd2VlaywgeT1BY2N1bXVsYXRlZF9jYXNlcywgDQogICAgICAgICAgICAgZmlsbD1BY2N1bXVsYXRlZF9jYXNlcyA+IDIwLA0KICAgICAgICAgICAgIGdyb3VwPWFzLmZhY3RvcihQT0FfTkFNRTE2KSkpICsgDQogIGdlb21fY29sKGNvbD0id2hpdGUiLCBzaXplPS4xKSArIA0KICBnZ3gocm91bmQsIHBibj0xMikgKw0KICBnZ2YoZmMgPSBEQ1syOjFdKSArIA0KICBnZ2woInRvcCIsIGx0ID0gVCkNCmBgYA0KDQoNCmBgYHtyLCBmaWcud2lkdGg9OCwgZmlnLmhlaWdodD01fQ0KY29uZmlybWVkX2Nhc2VzICU+JSANCiAgZmlsdGVyKGFzLmNoYXJhY3Rlcihwb3N0Y29kZSkgJWluJSBTWURfUE9BJFBPQV9OQU1FMTYpICU+JSANCiAgZmlsdGVyKHllYXIobm90aWZpY2F0aW9uX2RhdGUpID09IDIwMjAsIA0KICAgICAgICAgIyBtb250aChub3RpZmljYXRpb25fZGF0ZSkgJWluJSAzOjUsIA0KICAgICAgICAgaXNvd2Vlayhub3RpZmljYXRpb25fZGF0ZSkgJWluJSAxMDoyMykgJT4lIA0KICBmaWx0ZXIoYXMuY2hhcmFjdGVyKHBvc3Rjb2RlKSAlaW4lIFNZRF9QT0EkUE9BX05BTUUxNikgJT4lIA0KICBtdXRhdGUoaXNvd2VlayA9IGlzb3dlZWsobm90aWZpY2F0aW9uX2RhdGUpKSAlPiUgDQogIGNvdW50KGlzb3dlZWssIHBvc3Rjb2RlLCBuYW1lPSJUb3RhbF9jYXNlcyIpICU+JSANCiAgY29tcGxldGUoaXNvd2VlaywgcG9zdGNvZGUsIGZpbGwgPSBsaXN0KFRvdGFsX2Nhc2VzPTApKSAlPiUgDQogIGdyb3VwX2J5KHBvc3Rjb2RlKSAlPiUgDQogIG11dGF0ZShBY2N1bXVsYXRlZF9jYXNlcyA9IGN1bXN1bShUb3RhbF9jYXNlcykpICU+JSANCiAgZ3JvdXBfYnkoaXNvd2VlaykgJT4lIA0KICBtdXRhdGUoQWNjdW11bGF0ZWRfc2hhcmUgPSAoQWNjdW11bGF0ZWRfY2FzZXMvc3VtKEFjY3VtdWxhdGVkX2Nhc2VzLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYS5ybT1UKSkpICU+JQ0KICBtdXRhdGUoZmFjZXRfdmFyID0gcGFzdGUwKCJ3ZWVrICIsIGlzb3dlZWssIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICJcbkFjY3VtdWxhdGVkOiAiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb21tYShzdW0oQWNjdW11bGF0ZWRfY2FzZXMpKSkpICU+JSANCiAgcmVuYW1lKFBPQV9OQU1FMTYgPSBwb3N0Y29kZSkgJT4lIA0KICBtdXRhdGUoUE9BX05BTUUxNiA9IGZjdF9yZW9yZGVyKGFzLmZhY3RvcihQT0FfTkFNRTE2KSwgVG90YWxfY2FzZXMpKSAlPiUgDQogIHVuZ3JvdXAoKSAlPiUgDQogIGZpbHRlcighaXMubmEoaXNvd2VlaykpICU+JSANCiAgDQogIGdncGxvdChhZXMoeD1BY2N1bXVsYXRlZF9zaGFyZSwgZmlsbD1hcy5mYWN0b3IoaXNvd2VlaykpKSArIA0KICAjIGdlb21fZGVuc2l0eSgpICsgDQogIGdlb21faGlzdG9ncmFtKCkgKyANCiAgZmFjZXRfd3JhcCh+aXNvd2VlaywgbnJvdyA9IDMsIGxhYmVsbGVyID0gImxhYmVsX2JvdGgiKSArIA0KICB4bGltKDAsLjAzKSArIA0KICB5bGltKDAsNDApICsNCiAgZ2dsKCJub25lIikNCmBgYA0KDQojIExvY2FsIFBPSQ0KIyMgUHVibGljIHRyYW5zcG9ydA0KDQpgYGB7ciwgZmlnLndpZHRoPTkuNSwgZmlnLmhlaWdodD03fQ0KY29uZmlybWVkX2Nhc2VzICU+JSANCiAgICBmaWx0ZXIoYXMuY2hhcmFjdGVyKHBvc3Rjb2RlKSAlaW4lIFNZRF9QT0EkUE9BX05BTUUxNikgJT4lIA0KICAgIGNvdW50KHBvc3Rjb2RlLCBuYW1lPSJUb3RhbF9jYXNlcyIpICU+JSANCiAgICByZW5hbWUoUE9BX05BTUUxNiA9IHBvc3Rjb2RlKSAlPiUgDQogICAgbXV0YXRlKFBPQV9OQU1FMTYgPSBmY3RfcmVvcmRlcihhcy5mYWN0b3IoUE9BX05BTUUxNiksIFRvdGFsX2Nhc2VzKSkgJT4lIA0KICAgIHBsb3RfbWFwX1RMKFNZRF9QT0EsICJQT0FfTkFNRTE2IiwgIlRvdGFsX2Nhc2VzIiwgZmlsbF9jb2wgPSAiZ3JleTMzIiwNCiAgICAgICAgICAgICAgICAiVG90YWwgQ292aWQtMTkgY2FzZXMgYnkgUE9BIChTWUQpLCB3aXRoIHB1YmxpYyB0cmFuc3BvcnQiLCANCiAgICAgICAgICAgICAgICBzaG93X2NvdW50ID0gVCwgbGFiZWxfc2l6ZSA9IDIsIHJldHVybl9vYmogPSAibWFwIikgKw0KICANCiAgIyBnZW9tX21hcChpbmhlcml0LmFlcyA9IEZBTFNFLCBhbHBoYT0uODUsDQogICMgICAgICAgICAgYWVzKG1hcF9pZCA9IGlkKSwgbWFwID0gdGlkeShTWURfUE9BKSwgDQogICMgICAgICAgICAgY29sPSJncmV5NTAiLCBzaXplPS4zLCBmaWxsPSJ3aGl0ZSIpICsNCiAgZ2VvbV9saW5lKGRhdGEgPSBTWURfdHJhaW5zLCANCiAgICAgICAgICAgIGFlcyh4PWxvbiwgeT1sYXQsIGNvbD0iVHJhaW4iLA0KICAgICAgICAgICAgICAgIGdyb3VwID0gYFJhaWx3YXkgbGluZShzKWApLA0KICAgICAgICAgICAgc2l6ZT0uOCkgKw0KICBnZW9tX2xpbmUoZGF0YSA9IFNZRF9mZXJyaWVzLCANCiAgICAgICAgICAgIGFlcyh4PWxvbiwgeT1sYXQsIGNvbD0iRmVycnkiKSwNCiAgICAgICAgICAgICBzaXplPS44KSArDQogIGdlb21fbGluZShkYXRhID0gU1lEX2xpZ2h0cmFpbHMsIA0KICAgICAgICAgICAgYWVzKHg9bG9uLCB5PWxhdCwgY29sPSJMaWdodHJhaWwiKSwNCiAgICAgICAgICAgICBzaXplPS44KSArDQogIGdlb21fbGluZShkYXRhID0gU1lEX21ldHJvLCANCiAgICAgICAgICAgIGFlcyh4PWxvbiwgeT1sYXQsIGNvbD0iTWV0cm8iKSwNCiAgICAgICAgICAgICBzaXplPS44KSArDQogIGdnYyhjKCJkZWVwc2t5Ymx1ZSIsICJyZWQiLCAiZGFya2dyZWVuIiwgIm9yYW5nZSIpKSArIA0KICBndWlkZXMoY29sPWd1aWRlX2xlZ2VuZCh0aXRsZT0iVHJhbnNwb3J0X21vZGUiKSkgKyANCiAgZXhwYW5kX2xpbWl0cyh4ID0gdGlkeShTWURfUE9BKSRsb25nLCB5ID0gdGlkeShTWURfUE9BKSRsYXQpICsNCiAgY29vcmRfY2FydGVzaWFuKHhsaW0gPSBjKDE1MC43LCAxNTEuNDgpLCB5bGltID0gYygtMzQuMSwgLTMzLjUpKSArDQogIHRoZW1lX3ZvaWQoKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9IGMoLjksLjM1KSkNCmBgYA0KDQoNCiMjIEhvc3BpdGFscywgU2Nob29scywgU3VwZXJtYXJrZXQNCg0KYGBge3IsIGZpZy53aWR0aD05LjUsIGZpZy5oZWlnaHQ9OH0NCmJpbmRfcm93cygNCiAgU1lEX3Nob3BzICU+JSBzZWxlY3QobG9uLCBsYXQpICU+JSANCiAgICByZW5hbWUoTG9uZyA9IGxvbiwgTGF0ID0gbGF0KSAlPiUgbXV0YXRlKG9iaiA9ICJTaG9wcGluZyBjZW50cmVzIiksIA0KICBTWURfc3VwZXJtYXJrZXRzICU+JSBzZWxlY3QobG9uLCBsYXQpICU+JSANCiAgICByZW5hbWUoTG9uZyA9IGxvbiwgTGF0ID0gbGF0KSAlPiUgbXV0YXRlKG9iaiA9ICJTdXBlcm1hcmtldHMiKSwgDQogIFNZRF9ob3NwaXRhbHMgJT4lIHNlbGVjdChMb25naXR1ZGUsIExhdGl0dWRlKSAlPiUgDQogICAgcmVuYW1lKExvbmcgPSBMb25naXR1ZGUsIExhdCA9IExhdGl0dWRlKSAlPiUgbXV0YXRlKG9iaiA9ICJIb3NwaXRhbHMiKSwgDQogIHJiaW5kKFNZRF9zc2Nob29scyAlPiUgc2VsZWN0KExvbmcsIExhdCksDQogICAgICAgIFNZRF9wc2Nob29scyAlPiUgc2VsZWN0KExvbmcsIExhdCkpICU+JSBtdXRhdGUob2JqID0gIlNjaG9vbHMiKQ0KKSAlPiUgDQogIGdncGxvdCgpICsgIA0KICBnZW9tX21hcChkYXRhID0gU1lEX1BPQSwgaW5oZXJpdC5hZXMgPSBGQUxTRSwgYWxwaGE9Ljg1LA0KICAgICAgICAgICBhZXMobWFwX2lkID0gaWQpLCBtYXAgPSB0aWR5KFNZRF9QT0EpLCANCiAgICAgICAgICAgY29sPSJncmV5NTAiLCBzaXplPS4yLCBmaWxsPSJ3aGl0ZSIpICsNCiAgZ2VvbV9qaXR0ZXIoYWVzKHg9TG9uZywgeT1MYXQsIGNvbD1vYmopLCBzaXplPS44LCBhbHBoYT0uNSkgKyANCiAgc3RhdF9kZW5zaXR5MmQoYWVzKHg9TG9uZywgeT1MYXQsIA0KICAgICAgICAgICAgICAgICAgICAgZmlsbD0uLmxldmVsLi4sIGFscGhhPS4ubGV2ZWwuLiwgY29sPW9iaiksDQogICAgICAgICAgICAgICAgIGJpbndpZHRoID0gMS4yLCBnZW9tPSJwb2x5Z29uIiwgc2l6ZT0uMjMpICsgDQogIGZhY2V0X3dyYXAofm9iaikgKw0KICBleHBhbmRfbGltaXRzKHggPSB0aWR5KFNZRF9QT0EpJGxvbmcsIHkgPSB0aWR5KFNZRF9QT0EpJGxhdCkgKw0KICB4bGltKDE1MC43LDE1MS40OCkgKyB5bGltKC0zNC4xLC0zMy41KSArDQogIHNjYWxlX2ZpbGxfZ3JhZGllbnQobG93PSJ3aGl0ZSIsIGhpZ2g9RENbN10pICsgDQogIHNjYWxlX2FscGhhX2NvbnRpbnVvdXMocmFuZ2UgPSBjKDAsLjMpKSArIA0KICBnZ2MoZmMgPSBjKCJkYXJrcmVkIiwgImRlZXBza3libHVlIiwgImRhcmtibHVlIiwgImRhcmtncmVlbiIpKSArIA0KICB0aGVtZV92b2lkKCkgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsIA0KICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksIA0KICAgICAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9MTUpKQ0KYGBgDQoNCmBgYHtyLCBmaWcud2lkdGg9OS41LCBmaWcuaGVpZ2h0PTd9DQpjb25maXJtZWRfY2FzZXMgJT4lIA0KICBmaWx0ZXIoYXMuY2hhcmFjdGVyKHBvc3Rjb2RlKSAlaW4lIFNZRF9QT0EkUE9BX05BTUUxNikgJT4lIA0KICBjb3VudChwb3N0Y29kZSwgbmFtZT0iVG90YWxfY2FzZXMiKSAlPiUgDQogIHJlbmFtZShQT0FfTkFNRTE2ID0gcG9zdGNvZGUpICU+JSANCiAgbXV0YXRlKFBPQV9OQU1FMTYgPSBmY3RfcmVvcmRlcihhcy5mYWN0b3IoUE9BX05BTUUxNiksIFRvdGFsX2Nhc2VzKSkgJT4lIA0KICBwbG90X21hcF9UTChTWURfUE9BLCAiUE9BX05BTUUxNiIsICJUb3RhbF9jYXNlcyIsIGZpbGxfY29sID0gImdyZXkzMyIsDQogICAgICAgICAgICAgICJUb3RhbCBDb3ZpZC0xOSBjYXNlcyBieSBQT0EgKFNZRCksIHdpdGggaG9zcGl0YWxzLCBzY2hvb2xzICYgc3VwZXJtYXJrZXRzIiwgDQogICAgICAgICAgICAgIHNob3dfY291bnQgPSBULCBsYWJlbF9zaXplID0gMiwgcmV0dXJuX29iaiA9ICJtYXAiKSArDQogIA0KICAjIGdlb21fbWFwKGRhdGEgPSBTWURfUE9BLCBpbmhlcml0LmFlcyA9IEZBTFNFLCBhbHBoYT0uODUsDQogICMgICAgICAgICAgYWVzKG1hcF9pZCA9IGlkKSwgbWFwID0gdGlkeShTWURfUE9BKSwgDQogICMgICAgICAgICAgY29sPSJncmV5NTAiLCBzaXplPS4zLCBmaWxsPSJ3aGl0ZSIpICsNCiAgZ2VvbV9qaXR0ZXIoZGF0YSA9IGJpbmRfcm93cygNCiAgICBTWURfc2hvcHMgJT4lIHNlbGVjdChsb24sIGxhdCkgJT4lIA0KICAgICAgcmVuYW1lKExvbmcgPSBsb24sIExhdCA9IGxhdCkgJT4lIG11dGF0ZShvYmogPSAiU2hvcHBpbmcgY2VudHJlcyIpLCANCiAgICBTWURfc3VwZXJtYXJrZXRzICU+JSBzZWxlY3QobG9uLCBsYXQpICU+JSANCiAgICAgIHJlbmFtZShMb25nID0gbG9uLCBMYXQgPSBsYXQpICU+JSBtdXRhdGUob2JqID0gIlN1cGVybWFya2V0cyIpLCANCiAgICBTWURfaG9zcGl0YWxzICU+JSBzZWxlY3QoTG9uZ2l0dWRlLCBMYXRpdHVkZSkgJT4lIA0KICAgICAgcmVuYW1lKExvbmcgPSBMb25naXR1ZGUsIExhdCA9IExhdGl0dWRlKSAlPiUgbXV0YXRlKG9iaiA9ICJIb3NwaXRhbHMiKSwgDQogICAgcmJpbmQoU1lEX3NzY2hvb2xzICU+JSBzZWxlY3QoTG9uZywgTGF0KSwNCiAgICAgICAgICBTWURfcHNjaG9vbHMgJT4lIHNlbGVjdChMb25nLCBMYXQpKSAlPiUgbXV0YXRlKG9iaiA9ICJTY2hvb2xzIikNCiAgKSwgDQogIHNpemUgPSAxLCBhbHBoYSA9IC4zLCBhZXMoeD1Mb25nLCB5PUxhdCxjb2w9b2JqKSkgKw0KICBleHBhbmRfbGltaXRzKHggPSB0aWR5KFNZRF9QT0EpJGxvbmcsIHkgPSB0aWR5KFNZRF9QT0EpJGxhdCkgKw0KICB4bGltKDE1MC43LDE1MS40OCkgKyB5bGltKC0zNC4xLC0zMy41KSArDQogICMgc2NhbGVfZmlsbF9ncmFkaWVudChsb3c9IndoaXRlIiwgaGlnaD1EQ1s3XSkgKyANCiAgc2NhbGVfYWxwaGFfY29udGludW91cyhyYW5nZSA9IGMoMCwuMykpICsgDQogIGdnYyhmYyA9IGMoImRhcmtyZWQiLCAiZGFya2JsdWUiLCAiZGFya29yYW5nZSIsICJkYXJrZ3JlZW4iKSkgKyANCiAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZT0zKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aXRsZT0iUE9JIikpICsgDQogIHRoZW1lX3ZvaWQoKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9IGMoLjksLjI1KSwgDQogICAgICAgICMgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLCANCiAgICAgICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTE1KSkNCmBgYA0KIyMgUE9JIGNvbWJpbmVkDQoNCmBgYHtyLCBmaWcud2lkdGg9OS41LCBmaWcuaGVpZ2h0PTd9DQpjb25maXJtZWRfY2FzZXMgJT4lIA0KICBmaWx0ZXIoYXMuY2hhcmFjdGVyKHBvc3Rjb2RlKSAlaW4lIFNZRF9QT0EkUE9BX05BTUUxNikgJT4lIA0KICBjb3VudChwb3N0Y29kZSwgbmFtZT0iVG90YWxfY2FzZXMiKSAlPiUgDQogIHJlbmFtZShQT0FfTkFNRTE2ID0gcG9zdGNvZGUpICU+JSANCiAgbXV0YXRlKFBPQV9OQU1FMTYgPSBmY3RfcmVvcmRlcihhcy5mYWN0b3IoUE9BX05BTUUxNiksIFRvdGFsX2Nhc2VzKSkgJT4lIA0KICBwbG90X21hcF9UTChTWURfUE9BLCAiUE9BX05BTUUxNiIsICJUb3RhbF9jYXNlcyIsIGZpbGxfY29sID0gImdyZXkzMyIsDQogICAgICAgICAgICAgICJUb3RhbCBDb3ZpZC0xOSBjYXNlcyBieSBQT0EgKFNZRCksIHdpdGggaG9zcGl0YWxzLCBzY2hvb2xzICYgc3VwZXJtYXJrZXRzIiwgDQogICAgICAgICAgICAgIHNob3dfY291bnQgPSBULCBsYWJlbF9zaXplID0gMiwgcmV0dXJuX29iaiA9ICJtYXAiKSArDQogIGdlb21fbGluZShkYXRhID0gU1lEX3RyYWlucywgDQogICAgICAgICAgICBhZXMoeD1sb24sIHk9bGF0LCBjb2w9IlRyYWluIiwNCiAgICAgICAgICAgICAgICBncm91cCA9IGBSYWlsd2F5IGxpbmUocylgKSwNCiAgICAgICAgICAgIHNpemU9LjgpICsNCiAgZ2VvbV9saW5lKGRhdGEgPSBTWURfZmVycmllcywgDQogICAgICAgICAgICBhZXMoeD1sb24sIHk9bGF0LCBjb2w9IkZlcnJ5IiksDQogICAgICAgICAgICAgc2l6ZT0uOCkgKw0KICBnZW9tX2xpbmUoZGF0YSA9IFNZRF9saWdodHJhaWxzLCANCiAgICAgICAgICAgIGFlcyh4PWxvbiwgeT1sYXQsIGNvbD0iTGlnaHRyYWlsIiksDQogICAgICAgICAgICAgc2l6ZT0uOCkgKw0KICBnZW9tX2xpbmUoZGF0YSA9IFNZRF9tZXRybywgDQogICAgICAgICAgICBhZXMoeD1sb24sIHk9bGF0LCBjb2w9Ik1ldHJvIiksDQogICAgICAgICAgICAgc2l6ZT0uOCkgKw0KICANCiAgIyBnZW9tX21hcChkYXRhID0gU1lEX1BPQSwgaW5oZXJpdC5hZXMgPSBGQUxTRSwgYWxwaGE9Ljg1LA0KICAjICAgICAgICAgIGFlcyhtYXBfaWQgPSBpZCksIG1hcCA9IHRpZHkoU1lEX1BPQSksIA0KICAjICAgICAgICAgIGNvbD0iZ3JleTUwIiwgc2l6ZT0uMywgZmlsbD0id2hpdGUiKSArDQogIGdlb21faml0dGVyKGRhdGEgPSBiaW5kX3Jvd3MoDQogICAgU1lEX3Nob3BzICU+JSBzZWxlY3QobG9uLCBsYXQpICU+JSANCiAgICAgIHJlbmFtZShMb25nID0gbG9uLCBMYXQgPSBsYXQpICU+JSBtdXRhdGUob2JqID0gIlNob3BwaW5nIGNlbnRyZXMiKSwgDQogICAgU1lEX3N1cGVybWFya2V0cyAlPiUgc2VsZWN0KGxvbiwgbGF0KSAlPiUgDQogICAgICByZW5hbWUoTG9uZyA9IGxvbiwgTGF0ID0gbGF0KSAlPiUgbXV0YXRlKG9iaiA9ICJTdXBlcm1hcmtldHMiKSwgDQogICAgU1lEX2hvc3BpdGFscyAlPiUgc2VsZWN0KExvbmdpdHVkZSwgTGF0aXR1ZGUpICU+JSANCiAgICAgIHJlbmFtZShMb25nID0gTG9uZ2l0dWRlLCBMYXQgPSBMYXRpdHVkZSkgJT4lIG11dGF0ZShvYmogPSAiSG9zcGl0YWxzIiksIA0KICAgIHJiaW5kKFNZRF9zc2Nob29scyAlPiUgc2VsZWN0KExvbmcsIExhdCksDQogICAgICAgICAgU1lEX3BzY2hvb2xzICU+JSBzZWxlY3QoTG9uZywgTGF0KSkgJT4lIG11dGF0ZShvYmogPSAiU2Nob29scyIpDQogICksIA0KICBzaXplID0gMSwgYWxwaGEgPSAuMywgYWVzKHg9TG9uZywgeT1MYXQsY29sPW9iaikpICsNCiAgZXhwYW5kX2xpbWl0cyh4ID0gdGlkeShTWURfUE9BKSRsb25nLCB5ID0gdGlkeShTWURfUE9BKSRsYXQpICsNCiAgeGxpbSgxNTAuNywxNTEuNDgpICsgeWxpbSgtMzQuMSwtMzMuNSkgKw0KICAjIHNjYWxlX2ZpbGxfZ3JhZGllbnQobG93PSJ3aGl0ZSIsIGhpZ2g9RENbN10pICsgDQogIHNjYWxlX2FscGhhX2NvbnRpbnVvdXMocmFuZ2UgPSBjKDAsLjMpKSArIA0KICBnZ2MoZmMgPSBjKCJkZWVwc2t5Ymx1ZSIsICJkYXJrYmx1ZSIsICJyZWQiLCAiZGFya2dyZWVuIiwgDQogICAgICAgICAgICAgImRhcmtibHVlIiwgInJlZCIsICJkYXJrZ3JlZW4iLCAib3JhbmdlIikpICsgDQogIGd1aWRlcyhjb2xvciA9IGd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXMgPSBsaXN0KHNpemU9MyksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGl0bGU9IlBPSSIpKSArIA0KICB0aGVtZV92b2lkKCkgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSBjKC45LC40KSwgDQogICAgICAgICMgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLCANCiAgICAgICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTE1KSkNCmBgYA0KDQojIyBQT0kgY291bnQgUUEgey50YWJzZXR9DQojIyMgSG9zcGl0YWwNCg0KYGBge3IsIGZpZy53aWR0aD05LjUsIGZpZy5oZWlnaHQ9N30NCm5fcG9pX2J5X1BPQSAlPiUgDQogIGZpbHRlcihQT0FfTkFNRTE2ICE9ICJVbmtub3duIikgJT4lIA0KICAjIGdhdGhlcihrZXksIHZhbHVlLCAtUE9BX05BTUUxNikgJT4lIA0KICBzZWxlY3QoUE9BX05BTUUxNiwgbl9ob3NwaXRhbHMpICU+JSANCiAgbXV0YXRlKFBPQV9OQU1FMTYgPSBmY3RfcmVvcmRlcihQT0FfTkFNRTE2LCBuX2hvc3BpdGFscykpICU+JSANCiAgcGxvdF9tYXBfVEwoU1lEX1BPQSwgIlBPQV9OQU1FMTYiLCAibl9ob3NwaXRhbHMiLCANCiAgICAgICAgICAgICAgIk51bWJlciBvZiBob3NwaXRhbHMgYnkgUE9BIiwgDQogICAgICAgICAgICAgIHNob3dfY291bnQgPSBULCBmaWxsX2NvbCA9ICJkYXJrcmVkIikNCmBgYA0KDQojIyMgU2Nob29scw0KDQpgYGB7ciwgZmlnLndpZHRoPTkuNSwgZmlnLmhlaWdodD03fQ0Kbl9wb2lfYnlfUE9BICU+JSANCiAgZmlsdGVyKFBPQV9OQU1FMTYgIT0gIlVua25vd24iKSAlPiUgDQogICMgZ2F0aGVyKGtleSwgdmFsdWUsIC1QT0FfTkFNRTE2KSAlPiUgDQogIHNlbGVjdChQT0FfTkFNRTE2LCBuX3NjaG9vbHMpICU+JSANCiAgbXV0YXRlKFBPQV9OQU1FMTYgPSBmY3RfcmVvcmRlcihQT0FfTkFNRTE2LCBuX3NjaG9vbHMpKSAlPiUgDQogIHBsb3RfbWFwX1RMKFNZRF9QT0EsICJQT0FfTkFNRTE2IiwgIm5fc2Nob29scyIsIA0KICAgICAgICAgICAgICAiTnVtYmVyIG9mIHNjaG9vbHMgYnkgUE9BIiwgDQogICAgICAgICAgICAgIHNob3dfY291bnQgPSBULCBmaWxsX2NvbCA9ICJkZWVwc2t5Ymx1ZSIpDQpgYGANCg0KDQojIyMgU3VwZXJtYXJrZXRzDQoNCmBgYHtyLCBmaWcud2lkdGg9OS41LCBmaWcuaGVpZ2h0PTd9DQpuX3BvaV9ieV9QT0EgJT4lIA0KICBmaWx0ZXIoUE9BX05BTUUxNiAhPSAiVW5rbm93biIpICU+JSANCiAgIyBnYXRoZXIoa2V5LCB2YWx1ZSwgLVBPQV9OQU1FMTYpICU+JSANCiAgc2VsZWN0KFBPQV9OQU1FMTYsIG5fc3VwZXJtYXJrZXRzKSAlPiUgDQogIG11dGF0ZShQT0FfTkFNRTE2ID0gZmN0X3Jlb3JkZXIoUE9BX05BTUUxNiwgbl9zdXBlcm1hcmtldHMpKSAlPiUgDQogIHBsb3RfbWFwX1RMKFNZRF9QT0EsICJQT0FfTkFNRTE2IiwgIm5fc3VwZXJtYXJrZXRzIiwgDQogICAgICAgICAgICAgICJOdW1iZXIgb2Ygc3VwZXJtYXJrZXRzIGJ5IFBPQSIsIA0KICAgICAgICAgICAgICBzaG93X2NvdW50ID0gVCwgZmlsbF9jb2wgPSAiZGFya2dyZWVuIikNCmBgYA0KDQoNCiMjIyBTaG9wcGluZyBjZW50cmVzDQoNCmBgYHtyLCBmaWcud2lkdGg9OS41LCBmaWcuaGVpZ2h0PTd9DQpuX3BvaV9ieV9QT0EgJT4lIA0KICBmaWx0ZXIoUE9BX05BTUUxNiAhPSAiVW5rbm93biIpICU+JSANCiAgIyBnYXRoZXIoa2V5LCB2YWx1ZSwgLVBPQV9OQU1FMTYpICU+JSANCiAgc2VsZWN0KFBPQV9OQU1FMTYsIG5fc2hvcHBpbmdDZW50cmVzKSAlPiUgDQogIG11dGF0ZShQT0FfTkFNRTE2ID0gZmN0X3Jlb3JkZXIoUE9BX05BTUUxNiwgbl9zaG9wcGluZ0NlbnRyZXMpKSAlPiUgDQogIHBsb3RfbWFwX1RMKFNZRF9QT0EsICJQT0FfTkFNRTE2IiwgIm5fc2hvcHBpbmdDZW50cmVzIiwgDQogICAgICAgICAgICAgICJOdW1iZXIgb2Ygc2hvcHBpbmcgY2VudHJlcyBieSBQT0EiLCANCiAgICAgICAgICAgICAgc2hvd19jb3VudCA9IFQsIGZpbGxfY29sID0gImJsYWNrIikNCmBgYA0KDQojIyMgUHVibGljIHRyYW5zcG9ydHMNCg0KYGBge3IsIGZpZy53aWR0aD05LjUsIGZpZy5oZWlnaHQ9N30NCm5fcG9pX2J5X1BPQSAlPiUgDQogIGZpbHRlcihQT0FfTkFNRTE2ICE9ICJVbmtub3duIikgJT4lIA0KICAjIGdhdGhlcihrZXksIHZhbHVlLCAtUE9BX05BTUUxNikgJT4lIA0KICBzZWxlY3QoUE9BX05BTUUxNiwgbl9wdWJsaWNUcmFuc3BvcnRzICkgJT4lIA0KICBtdXRhdGUoUE9BX05BTUUxNiA9IGZjdF9yZW9yZGVyKFBPQV9OQU1FMTYsIG5fcHVibGljVHJhbnNwb3J0cyApKSAlPiUgDQogIHBsb3RfbWFwX1RMKFNZRF9QT0EsICJQT0FfTkFNRTE2IiwgIm5fcHVibGljVHJhbnNwb3J0cyIsIA0KICAgICAgICAgICAgICAiTnVtYmVyIG9mIHB1YmxpYyB0cmFuc3BvcnRzIGJ5IFBPQSIsIA0KICAgICAgICAgICAgICBzaG93X2NvdW50ID0gVCwgZmlsbF9jb2wgPSAiZGFya29yYW5nZSIpDQpgYGANCg0KIyBHcmF2aXR5DQojIyBTb3V0aCBFYXN0ZXJuIFNZRCAoMjAyNikgey50YWJzZXR9DQojIyMgUmFkaWFsIGRpc3RhbmNlDQoNCmBgYHtyLCBmaWcud2lkdGg9OS41LCBmaWcuaGVpZ2h0PTd9DQooDQpwbG90X2dyYXZpdHlfbWFwX1RMKG5fcG9pX2J5X1BPQSwgIjIwMjYiLCAibl9ob3NwaXRhbHMiKSArIA0KICB4bGltKDE1MS4xLDE1MS4zMykgKyB5bGltKC0zNCwtMzMuNykgfCANCnBsb3RfZ3Jhdml0eV9tYXBfVEwobl9wb2lfYnlfUE9BLCAiMjAyNiIsICJuX3NjaG9vbHMiKSArIA0KICB4bGltKDE1MS4xLDE1MS4zMykgKyB5bGltKC0zNCwtMzMuNykgfA0KcGxvdF9ncmF2aXR5X21hcF9UTChuX3BvaV9ieV9QT0EsICIyMDI2IiwgIm5fc3VwZXJtYXJrZXRzIikgKyANCiAgeGxpbSgxNTEuMSwxNTEuMzMpICsgeWxpbSgtMzQsLTMzLjcpDQopIC8NCigNCnBsb3RfZ3Jhdml0eV9tYXBfVEwobl9wb2lfYnlfUE9BLCAiMjAyNiIsICJuX3Nob3BwaW5nQ2VudHJlcyIpICsgDQogIHhsaW0oMTUxLjEsMTUxLjMzKSArIHlsaW0oLTM0LC0zMy43KSB8IA0KcGxvdF9ncmF2aXR5X21hcF9UTChuX3BvaV9ieV9QT0EsICIyMDI2IiwgIm5fcHVibGljVHJhbnNwb3J0cyIpICsgDQogIHhsaW0oMTUxLjEsMTUxLjMzKSArIHlsaW0oLTM0LC0zMy43KSB8IA0Kbl9wb2lfYnlfUE9BICU+JSANCiAgbXV0YXRlKGNvbWJpbmVkX2luZGV4ID0gDQogICAgICAgICAgIG5vcm1hbGlzZWRfbl9ob3NwaXRhbHMgKw0KICAgICAgICAgICBub3JtYWxpc2VkX25fc2Nob29scyArDQogICAgICAgICAgIG5vcm1hbGlzZWRfbl9zdXBlcm1hcmtldHMgKw0KICAgICAgICAgICBub3JtYWxpc2VkX25fc2hvcHBpbmdDZW50cmVzICsNCiAgICAgICAgICAgbm9ybWFsaXNlZF9uX3B1YmxpY1RyYW5zcG9ydHMNCiAgKSAlPiUgcGxvdF9ncmF2aXR5X21hcF9UTCgiMjAyNiIsICJjb21iaW5lZF9pbmRleCIpICsgDQogIHhsaW0oMTUxLjEsMTUxLjMzKSArIHlsaW0oLTM0LC0zMy43KQ0KKQ0KYGBgDQojIyMgVHJhdmVsIHRpbWUgZGlzdGFuY2UNCg0KYGBge3IsIGZpZy53aWR0aD05LjUsIGZpZy5oZWlnaHQ9N30NCigNCnBsb3RfZ3Jhdml0eV9tYXBfVEwobl9wb2lfYnlfUE9BLCAiMjAyNiIsICJuX2hvc3BpdGFscyIsIA0KICAgICAgICAgICAgICAgICAgICBkaXN0X21hdHJpeCA9IFNZRF9QT0FfbWFwZGlzdCAlPiUgbXV0YXRlKGRpc3QgPSBkaXN0LzEwMDApKSArIA0KICB4bGltKDE1MS4xLDE1MS4zMykgKyB5bGltKC0zNCwtMzMuNykgfCANCnBsb3RfZ3Jhdml0eV9tYXBfVEwobl9wb2lfYnlfUE9BLCAiMjAyNiIsICJuX3NjaG9vbHMiLCANCiAgICAgICAgICAgICAgICAgICAgZGlzdF9tYXRyaXggPSBTWURfUE9BX21hcGRpc3QgJT4lIG11dGF0ZShkaXN0ID0gZGlzdC8xMDAwKSkgKyANCiAgeGxpbSgxNTEuMSwxNTEuMzMpICsgeWxpbSgtMzQsLTMzLjcpIHwNCnBsb3RfZ3Jhdml0eV9tYXBfVEwobl9wb2lfYnlfUE9BLCAiMjAyNiIsICJuX3N1cGVybWFya2V0cyIsIA0KICAgICAgICAgICAgICAgICAgICBkaXN0X21hdHJpeCA9IFNZRF9QT0FfbWFwZGlzdCAlPiUgbXV0YXRlKGRpc3QgPSBkaXN0LzEwMDApKSArIA0KICB4bGltKDE1MS4xLDE1MS4zMykgKyB5bGltKC0zNCwtMzMuNykNCikgLw0KKA0KcGxvdF9ncmF2aXR5X21hcF9UTChuX3BvaV9ieV9QT0EsICIyMDI2IiwgIm5fc2hvcHBpbmdDZW50cmVzIiwgDQogICAgICAgICAgICAgICAgICAgIGRpc3RfbWF0cml4ID0gU1lEX1BPQV9tYXBkaXN0ICU+JSBtdXRhdGUoZGlzdCA9IGRpc3QvMTAwMCkpICsgDQogIHhsaW0oMTUxLjEsMTUxLjMzKSArIHlsaW0oLTM0LC0zMy43KSB8IA0KcGxvdF9ncmF2aXR5X21hcF9UTChuX3BvaV9ieV9QT0EsICIyMDI2IiwgIm5fcHVibGljVHJhbnNwb3J0cyIsIA0KICAgICAgICAgICAgICAgICAgICBkaXN0X21hdHJpeCA9IFNZRF9QT0FfbWFwZGlzdCAlPiUgbXV0YXRlKGRpc3QgPSBkaXN0LzEwMDApKSArIA0KICB4bGltKDE1MS4xLDE1MS4zMykgKyB5bGltKC0zNCwtMzMuNykgfCANCm5fcG9pX2J5X1BPQSAlPiUgDQogIG11dGF0ZShjb21iaW5lZF9pbmRleCA9IA0KICAgICAgICAgICBub3JtYWxpc2VkX25faG9zcGl0YWxzICsNCiAgICAgICAgICAgbm9ybWFsaXNlZF9uX3NjaG9vbHMgKw0KICAgICAgICAgICBub3JtYWxpc2VkX25fc3VwZXJtYXJrZXRzICsNCiAgICAgICAgICAgbm9ybWFsaXNlZF9uX3Nob3BwaW5nQ2VudHJlcyArDQogICAgICAgICAgIG5vcm1hbGlzZWRfbl9wdWJsaWNUcmFuc3BvcnRzDQogICkgJT4lIHBsb3RfZ3Jhdml0eV9tYXBfVEwoIjIwMjYiLCAiY29tYmluZWRfaW5kZXgiLCANCiAgICAgICAgICAgICAgICAgICAgZGlzdF9tYXRyaXggPSBTWURfUE9BX21hcGRpc3QgJT4lIG11dGF0ZShkaXN0ID0gZGlzdC8xMDAwKSkgKyANCiAgeGxpbSgxNTEuMSwxNTEuMzMpICsgeWxpbSgtMzQsLTMzLjcpDQopDQpgYGANCg0KIyMgV2VzdGVybiBTWUQgKDIxNDUpIHsudGFic2V0fQ0KIyMjIFJhZGlhbCBkaXN0YW5jZQ0KDQpgYGB7ciwgZmlnLndpZHRoPTkuNSwgZmlnLmhlaWdodD03fQ0KKA0KcGxvdF9ncmF2aXR5X21hcF9UTChuX3BvaV9ieV9QT0EsICIyMTQ1IiwgIm5faG9zcGl0YWxzIikgfCANCnBsb3RfZ3Jhdml0eV9tYXBfVEwobl9wb2lfYnlfUE9BLCAiMjE0NSIsICJuX3NjaG9vbHMiKSB8DQpwbG90X2dyYXZpdHlfbWFwX1RMKG5fcG9pX2J5X1BPQSwgIjIxNDUiLCAibl9zdXBlcm1hcmtldHMiKQ0KKSAvDQooDQpwbG90X2dyYXZpdHlfbWFwX1RMKG5fcG9pX2J5X1BPQSwgIjIxNDUiLCAibl9zaG9wcGluZ0NlbnRyZXMiKSB8IA0KcGxvdF9ncmF2aXR5X21hcF9UTChuX3BvaV9ieV9QT0EsICIyMTQ1IiwgIm5fcHVibGljVHJhbnNwb3J0cyIpIHwgDQpuX3BvaV9ieV9QT0EgJT4lIA0KICBtdXRhdGUoY29tYmluZWRfaW5kZXggPSANCiAgICAgICAgICAgbm9ybWFsaXNlZF9uX2hvc3BpdGFscyArDQogICAgICAgICAgIG5vcm1hbGlzZWRfbl9zY2hvb2xzICsNCiAgICAgICAgICAgbm9ybWFsaXNlZF9uX3N1cGVybWFya2V0cyArDQogICAgICAgICAgIG5vcm1hbGlzZWRfbl9zaG9wcGluZ0NlbnRyZXMgKw0KICAgICAgICAgICBub3JtYWxpc2VkX25fcHVibGljVHJhbnNwb3J0cw0KICApICU+JSBwbG90X2dyYXZpdHlfbWFwX1RMKCIyMTQ1IiwgImNvbWJpbmVkX2luZGV4IikNCikNCmBgYA0KIyMjIFRyYXZlbCB0aW1lIGRpc3RhbmNlDQoNCmBgYHtyLCBmaWcud2lkdGg9OS41LCBmaWcuaGVpZ2h0PTd9DQooDQpwbG90X2dyYXZpdHlfbWFwX1RMKG5fcG9pX2J5X1BPQSwgIjIxNDUiLCAibl9ob3NwaXRhbHMiLCANCiAgICAgICAgICAgICAgICAgICAgZGlzdF9tYXRyaXggPSBTWURfUE9BX21hcGRpc3QgJT4lIG11dGF0ZShkaXN0ID0gZGlzdC8xMDAwKSkgfCANCnBsb3RfZ3Jhdml0eV9tYXBfVEwobl9wb2lfYnlfUE9BLCAiMjE0NSIsICJuX3NjaG9vbHMiLCANCiAgICAgICAgICAgICAgICAgICAgZGlzdF9tYXRyaXggPSBTWURfUE9BX21hcGRpc3QgJT4lIG11dGF0ZShkaXN0ID0gZGlzdC8xMDAwKSkgfA0KcGxvdF9ncmF2aXR5X21hcF9UTChuX3BvaV9ieV9QT0EsICIyMTQ1IiwgIm5fc3VwZXJtYXJrZXRzIiwgDQogICAgICAgICAgICAgICAgICAgIGRpc3RfbWF0cml4ID0gU1lEX1BPQV9tYXBkaXN0ICU+JSBtdXRhdGUoZGlzdCA9IGRpc3QvMTAwMCkpDQopIC8NCigNCnBsb3RfZ3Jhdml0eV9tYXBfVEwobl9wb2lfYnlfUE9BLCAiMjE0NSIsICJuX3Nob3BwaW5nQ2VudHJlcyIsIA0KICAgICAgICAgICAgICAgICAgICBkaXN0X21hdHJpeCA9IFNZRF9QT0FfbWFwZGlzdCAlPiUgbXV0YXRlKGRpc3QgPSBkaXN0LzEwMDApKSB8IA0KcGxvdF9ncmF2aXR5X21hcF9UTChuX3BvaV9ieV9QT0EsICIyMTQ1IiwgIm5fcHVibGljVHJhbnNwb3J0cyIsIA0KICAgICAgICAgICAgICAgICAgICBkaXN0X21hdHJpeCA9IFNZRF9QT0FfbWFwZGlzdCAlPiUgbXV0YXRlKGRpc3QgPSBkaXN0LzEwMDApKSB8IA0Kbl9wb2lfYnlfUE9BICU+JSANCiAgbXV0YXRlKGNvbWJpbmVkX2luZGV4ID0gDQogICAgICAgICAgIG5vcm1hbGlzZWRfbl9ob3NwaXRhbHMgKw0KICAgICAgICAgICBub3JtYWxpc2VkX25fc2Nob29scyArDQogICAgICAgICAgIG5vcm1hbGlzZWRfbl9zdXBlcm1hcmtldHMgKw0KICAgICAgICAgICBub3JtYWxpc2VkX25fc2hvcHBpbmdDZW50cmVzICsNCiAgICAgICAgICAgbm9ybWFsaXNlZF9uX3B1YmxpY1RyYW5zcG9ydHMNCiAgKSAlPiUgcGxvdF9ncmF2aXR5X21hcF9UTCgiMjE0NSIsICJjb21iaW5lZF9pbmRleCIsIA0KICAgICAgICAgICAgICAgICAgICBkaXN0X21hdHJpeCA9IFNZRF9QT0FfbWFwZGlzdCAlPiUgbXV0YXRlKGRpc3QgPSBkaXN0LzEwMDApKQ0KKQ0KYGBgDQoNCiMjIE5vdGhlcm4gU1lEICgyMTA3KSB7LnRhYnNldH0NCiMjIyBSYWRpYWwgZGlzdGFuY2UNCg0KYGBge3IsIGZpZy53aWR0aD05LjUsIGZpZy5oZWlnaHQ9N30NCigNCnBsb3RfZ3Jhdml0eV9tYXBfVEwobl9wb2lfYnlfUE9BLCAiMjEwNyIsICJuX2hvc3BpdGFscyIpICsgDQogIHhsaW0oMTUxLDE1MS40KSArIHlsaW0oLTMzLjksLTMzLjUpIHwgDQpwbG90X2dyYXZpdHlfbWFwX1RMKG5fcG9pX2J5X1BPQSwgIjIxMDciLCAibl9zY2hvb2xzIikgKyANCiAgeGxpbSgxNTEsMTUxLjQpICsgeWxpbSgtMzMuOSwtMzMuNSkgfA0KcGxvdF9ncmF2aXR5X21hcF9UTChuX3BvaV9ieV9QT0EsICIyMTA3IiwgIm5fc3VwZXJtYXJrZXRzIikgKyANCiAgeGxpbSgxNTEsMTUxLjQpICsgeWxpbSgtMzMuOSwtMzMuNSkNCikgLw0KKA0KcGxvdF9ncmF2aXR5X21hcF9UTChuX3BvaV9ieV9QT0EsICIyMTA3IiwgIm5fc2hvcHBpbmdDZW50cmVzIikgKyANCiAgeGxpbSgxNTEsMTUxLjQpICsgeWxpbSgtMzMuOSwtMzMuNSkgfCANCnBsb3RfZ3Jhdml0eV9tYXBfVEwobl9wb2lfYnlfUE9BLCAiMjEwNyIsICJuX3B1YmxpY1RyYW5zcG9ydHMiKSArIA0KICB4bGltKDE1MSwxNTEuNCkgKyB5bGltKC0zMy45LC0zMy41KSB8IA0Kbl9wb2lfYnlfUE9BICU+JSANCiAgbXV0YXRlKGNvbWJpbmVkX2luZGV4ID0gDQogICAgICAgICAgIG5vcm1hbGlzZWRfbl9ob3NwaXRhbHMgKw0KICAgICAgICAgICBub3JtYWxpc2VkX25fc2Nob29scyArDQogICAgICAgICAgIG5vcm1hbGlzZWRfbl9zdXBlcm1hcmtldHMgKw0KICAgICAgICAgICBub3JtYWxpc2VkX25fc2hvcHBpbmdDZW50cmVzICsNCiAgICAgICAgICAgbm9ybWFsaXNlZF9uX3B1YmxpY1RyYW5zcG9ydHMNCiAgKSAlPiUgcGxvdF9ncmF2aXR5X21hcF9UTCgiMjEwNyIsICJjb21iaW5lZF9pbmRleCIpICsgDQogIHhsaW0oMTUxLDE1MS40KSArIHlsaW0oLTMzLjksLTMzLjUpDQopDQpgYGANCiMjIyBUcmF2ZWwgdGltZSBkaXN0YW5jZQ0KDQpgYGB7ciwgZmlnLndpZHRoPTkuNSwgZmlnLmhlaWdodD03fQ0KKA0KcGxvdF9ncmF2aXR5X21hcF9UTChuX3BvaV9ieV9QT0EsICIyMTA3IiwgIm5faG9zcGl0YWxzIiwgDQogICAgICAgICAgICAgICAgICAgIGRpc3RfbWF0cml4ID0gU1lEX1BPQV9tYXBkaXN0ICU+JSBtdXRhdGUoZGlzdCA9IGRpc3QvMTAwMCkpICsgDQogIHhsaW0oMTUxLDE1MS40KSArIHlsaW0oLTMzLjksLTMzLjUpIHwgDQpwbG90X2dyYXZpdHlfbWFwX1RMKG5fcG9pX2J5X1BPQSwgIjIxMDciLCAibl9zY2hvb2xzIiwgDQogICAgICAgICAgICAgICAgICAgIGRpc3RfbWF0cml4ID0gU1lEX1BPQV9tYXBkaXN0ICU+JSBtdXRhdGUoZGlzdCA9IGRpc3QvMTAwMCkpICsgDQogIHhsaW0oMTUxLDE1MS40KSArIHlsaW0oLTMzLjksLTMzLjUpIHwNCnBsb3RfZ3Jhdml0eV9tYXBfVEwobl9wb2lfYnlfUE9BLCAiMjEwNyIsICJuX3N1cGVybWFya2V0cyIsIA0KICAgICAgICAgICAgICAgICAgICBkaXN0X21hdHJpeCA9IFNZRF9QT0FfbWFwZGlzdCAlPiUgbXV0YXRlKGRpc3QgPSBkaXN0LzEwMDApKSArIA0KICB4bGltKDE1MSwxNTEuNCkgKyB5bGltKC0zMy45LC0zMy41KQ0KKSAvDQooDQpwbG90X2dyYXZpdHlfbWFwX1RMKG5fcG9pX2J5X1BPQSwgIjIxMDciLCAibl9zaG9wcGluZ0NlbnRyZXMiLCANCiAgICAgICAgICAgICAgICAgICAgZGlzdF9tYXRyaXggPSBTWURfUE9BX21hcGRpc3QgJT4lIG11dGF0ZShkaXN0ID0gZGlzdC8xMDAwKSkgKyANCiAgeGxpbSgxNTEsMTUxLjQpICsgeWxpbSgtMzMuOSwtMzMuNSkgfCANCnBsb3RfZ3Jhdml0eV9tYXBfVEwobl9wb2lfYnlfUE9BLCAiMjEwNyIsICJuX3B1YmxpY1RyYW5zcG9ydHMiLCANCiAgICAgICAgICAgICAgICAgICAgZGlzdF9tYXRyaXggPSBTWURfUE9BX21hcGRpc3QgJT4lIG11dGF0ZShkaXN0ID0gZGlzdC8xMDAwKSkgKyANCiAgeGxpbSgxNTEsMTUxLjQpICsgeWxpbSgtMzMuOSwtMzMuNSkgfCANCm5fcG9pX2J5X1BPQSAlPiUgDQogIG11dGF0ZShjb21iaW5lZF9pbmRleCA9IA0KICAgICAgICAgICBub3JtYWxpc2VkX25faG9zcGl0YWxzICsNCiAgICAgICAgICAgbm9ybWFsaXNlZF9uX3NjaG9vbHMgKw0KICAgICAgICAgICBub3JtYWxpc2VkX25fc3VwZXJtYXJrZXRzICsNCiAgICAgICAgICAgbm9ybWFsaXNlZF9uX3Nob3BwaW5nQ2VudHJlcyArDQogICAgICAgICAgIG5vcm1hbGlzZWRfbl9wdWJsaWNUcmFuc3BvcnRzDQogICkgJT4lIHBsb3RfZ3Jhdml0eV9tYXBfVEwoIjIxMDciLCAiY29tYmluZWRfaW5kZXgiLCANCiAgICAgICAgICAgICAgICAgICAgZGlzdF9tYXRyaXggPSBTWURfUE9BX21hcGRpc3QgJT4lIG11dGF0ZShkaXN0ID0gZGlzdC8xMDAwKSkgKyANCiAgeGxpbSgxNTEsMTUxLjQpICsgeWxpbSgtMzMuOSwtMzMuNSkNCikNCmBgYA0KDQojIFN1Z2dlc3RlZCAiaGlnaC1yaXNrIiBhcmVhDQojIyBTb3V0aCBFYXN0ZXJuIFNZRCAoMjAyNikNCg0KYGBge3J9DQpiaW5kX3Jvd3MoDQpjYWxjX2dyYXZpdHlfVEwobl9wb2lfYnlfUE9BLCAiMjAyNiIsICJuX2hvc3BpdGFscyIsIA0KICAgICAgICAgICAgICAgICAgICBkaXN0X21hdHJpeCA9IFNZRF9QT0FfbWFwZGlzdCAlPiUgbXV0YXRlKGRpc3QgPSBkaXN0LzEwMDApKQ0KLGNhbGNfZ3Jhdml0eV9UTChuX3BvaV9ieV9QT0EsICIyMDI2IiwgIm5fc2Nob29scyIsIA0KICAgICAgICAgICAgICAgICAgICBkaXN0X21hdHJpeCA9IFNZRF9QT0FfbWFwZGlzdCAlPiUgbXV0YXRlKGRpc3QgPSBkaXN0LzEwMDApKQ0KLGNhbGNfZ3Jhdml0eV9UTChuX3BvaV9ieV9QT0EsICIyMDI2IiwgIm5fc3VwZXJtYXJrZXRzIiwgDQogICAgICAgICAgICAgICAgICAgIGRpc3RfbWF0cml4ID0gU1lEX1BPQV9tYXBkaXN0ICU+JSBtdXRhdGUoZGlzdCA9IGRpc3QvMTAwMCkpDQosY2FsY19ncmF2aXR5X1RMKG5fcG9pX2J5X1BPQSwgIjIwMjYiLCAibl9zaG9wcGluZ0NlbnRyZXMiLCANCiAgICAgICAgICAgICAgICAgICAgZGlzdF9tYXRyaXggPSBTWURfUE9BX21hcGRpc3QgJT4lIG11dGF0ZShkaXN0ID0gZGlzdC8xMDAwKSkNCixjYWxjX2dyYXZpdHlfVEwobl9wb2lfYnlfUE9BLCAiMjAyNiIsICJuX3B1YmxpY1RyYW5zcG9ydHMiLCANCiAgICAgICAgICAgICAgICAgICAgZGlzdF9tYXRyaXggPSBTWURfUE9BX21hcGRpc3QgJT4lIG11dGF0ZShkaXN0ID0gZGlzdC8xMDAwKSkNCikgJT4lIA0KICBncm91cF9ieSh0YXJnZXQsIHNvdXJjZSkgJT4lIA0KICBzdW1tYXJpc2Uocmlza19mYWN0b3IgPSBzdW0oZ3Jhdml0eV9yYW5rKSkgJT4lIA0KICAjIHNsaWNlX21heChyaXNrX2ZhY3Rvciwgbj0xMSkgJT4lIA0KICAjIHBkZigpDQogIA0KICBsZWZ0X2pvaW4oDQogICAgY29uZmlybWVkX2Nhc2VzICU+JSANCiAgICAgIGZpbHRlcihub3RpZmljYXRpb25fZGF0ZSA8IHltZCgyMDIwMDcwMSkpICU+JSANCiAgICAgIGNvdW50KHBvc3Rjb2RlLCBuYW1lID0gInRvdGFsX2Nhc2VzIikgJT4lIA0KICAgICAgbXV0YXRlKHNvdXJjZSA9IGFzLmNoYXJhY3Rlcihwb3N0Y29kZSkpLCANCiAgICBieT0ic291cmNlIg0KICApICU+JSANCiAgbXV0YXRlKHRleHRfbGFiID0gaWZlbHNlKHRvdGFsX2Nhc2VzID49IDMwLCBzb3VyY2UsIE5BKSkgJT4lIA0KICBnZ3Bsb3QoYWVzKHg9cmlza19mYWN0b3IsIHk9dG90YWxfY2FzZXMpKSArIA0KICBnZW9tX3BvaW50KCkgKyANCiAgc3RhdF9zbW9vdGgoKSArIA0KICBnZW9tX3RleHRfcmVwZWwoYWVzKGxhYmVsPXRleHRfbGFiKSkgKyANCiAgbGFicyhzdWJ0aXRsZSA9ICJCYXNlZCBvbiB0b3RhbCBjYXNlcyBiZWZvcmUgZGF0ZSAyMDIwLTA3LTAxIikgKyANCiAgZ2dsKGJhc2Vfc2l6ZT0xMikNCmBgYA0KIyMgV2VzdGVybiBTWUQgKDIxNDUpDQoNCmBgYHtyfQ0KYmluZF9yb3dzKA0KY2FsY19ncmF2aXR5X1RMKG5fcG9pX2J5X1BPQSwgIjIxNDUiLCAibl9ob3NwaXRhbHMiLCANCiAgICAgICAgICAgICAgICAgICAgZGlzdF9tYXRyaXggPSBTWURfUE9BX21hcGRpc3QgJT4lIG11dGF0ZShkaXN0ID0gZGlzdC8xMDAwKSkNCixjYWxjX2dyYXZpdHlfVEwobl9wb2lfYnlfUE9BLCAiMjE0NSIsICJuX3NjaG9vbHMiLCANCiAgICAgICAgICAgICAgICAgICAgZGlzdF9tYXRyaXggPSBTWURfUE9BX21hcGRpc3QgJT4lIG11dGF0ZShkaXN0ID0gZGlzdC8xMDAwKSkNCixjYWxjX2dyYXZpdHlfVEwobl9wb2lfYnlfUE9BLCAiMjE0NSIsICJuX3N1cGVybWFya2V0cyIsIA0KICAgICAgICAgICAgICAgICAgICBkaXN0X21hdHJpeCA9IFNZRF9QT0FfbWFwZGlzdCAlPiUgbXV0YXRlKGRpc3QgPSBkaXN0LzEwMDApKQ0KLGNhbGNfZ3Jhdml0eV9UTChuX3BvaV9ieV9QT0EsICIyMTQ1IiwgIm5fc2hvcHBpbmdDZW50cmVzIiwgDQogICAgICAgICAgICAgICAgICAgIGRpc3RfbWF0cml4ID0gU1lEX1BPQV9tYXBkaXN0ICU+JSBtdXRhdGUoZGlzdCA9IGRpc3QvMTAwMCkpDQosY2FsY19ncmF2aXR5X1RMKG5fcG9pX2J5X1BPQSwgIjIxNDUiLCAibl9wdWJsaWNUcmFuc3BvcnRzIiwgDQogICAgICAgICAgICAgICAgICAgIGRpc3RfbWF0cml4ID0gU1lEX1BPQV9tYXBkaXN0ICU+JSBtdXRhdGUoZGlzdCA9IGRpc3QvMTAwMCkpDQopICU+JSANCiAgZ3JvdXBfYnkodGFyZ2V0LCBzb3VyY2UpICU+JSANCiAgc3VtbWFyaXNlKHJpc2tfZmFjdG9yID0gc3VtKGdyYXZpdHlfcmFuaykpICU+JSANCiAgIyBzbGljZV9tYXgocmlza19mYWN0b3IsIG49MTEpICU+JQ0KICAjIHBkZigpDQogIGxlZnRfam9pbigNCiAgICBjb25maXJtZWRfY2FzZXMgJT4lIA0KICAgICAgZmlsdGVyKG5vdGlmaWNhdGlvbl9kYXRlID49IHltZCgyMDIwMDcwMSksIA0KICAgICAgICAgICAgIG5vdGlmaWNhdGlvbl9kYXRlIDwgeW1kKDIwMjAxMTAxKSkgJT4lIA0KICAgICAgY291bnQocG9zdGNvZGUsIG5hbWUgPSAidG90YWxfY2FzZXMiKSAlPiUgDQogICAgICBtdXRhdGUoc291cmNlID0gYXMuY2hhcmFjdGVyKHBvc3Rjb2RlKSksIA0KICAgIGJ5PSJzb3VyY2UiDQogICkgJT4lIA0KICBtdXRhdGUodGV4dF9sYWIgPSBpZmVsc2UodG90YWxfY2FzZXMgPj0gMTUsIHNvdXJjZSwgTkEpKSAlPiUgDQogIGdncGxvdChhZXMoeD1yaXNrX2ZhY3RvciwgeT10b3RhbF9jYXNlcykpICsgDQogIGdlb21fcG9pbnQoKSArIA0KICBzdGF0X3Ntb290aCgpICsgDQogIGdlb21fdGV4dF9yZXBlbChhZXMobGFiZWw9dGV4dF9sYWIpKSArIA0KICBsYWJzKHN1YnRpdGxlID0gIkJhc2VkIG9uIHRvdGFsIGNhc2VzIGJldHdlZW4gZGF0ZSAyMDIwLTA3LTAxIGFuZCAyMDIwLTEyLTAxIikgKyANCiAgZ2dsKGJhc2Vfc2l6ZT0xMikNCmBgYA0KDQojIyBOb3RoZXJuIFNZRCAoMjEwNykNCg0KYGBge3J9DQpiaW5kX3Jvd3MoDQpjYWxjX2dyYXZpdHlfVEwobl9wb2lfYnlfUE9BLCAiMjEwNyIsICJuX2hvc3BpdGFscyIsIA0KICAgICAgICAgICAgICAgICAgICBkaXN0X21hdHJpeCA9IFNZRF9QT0FfbWFwZGlzdCAlPiUgbXV0YXRlKGRpc3QgPSBkaXN0LzEwMDApKQ0KLGNhbGNfZ3Jhdml0eV9UTChuX3BvaV9ieV9QT0EsICIyMTA3IiwgIm5fc2Nob29scyIsIA0KICAgICAgICAgICAgICAgICAgICBkaXN0X21hdHJpeCA9IFNZRF9QT0FfbWFwZGlzdCAlPiUgbXV0YXRlKGRpc3QgPSBkaXN0LzEwMDApKQ0KLGNhbGNfZ3Jhdml0eV9UTChuX3BvaV9ieV9QT0EsICIyMTA3IiwgIm5fc3VwZXJtYXJrZXRzIiwgDQogICAgICAgICAgICAgICAgICAgIGRpc3RfbWF0cml4ID0gU1lEX1BPQV9tYXBkaXN0ICU+JSBtdXRhdGUoZGlzdCA9IGRpc3QvMTAwMCkpDQosY2FsY19ncmF2aXR5X1RMKG5fcG9pX2J5X1BPQSwgIjIxMDciLCAibl9zaG9wcGluZ0NlbnRyZXMiLCANCiAgICAgICAgICAgICAgICAgICAgZGlzdF9tYXRyaXggPSBTWURfUE9BX21hcGRpc3QgJT4lIG11dGF0ZShkaXN0ID0gZGlzdC8xMDAwKSkNCixjYWxjX2dyYXZpdHlfVEwobl9wb2lfYnlfUE9BLCAiMjEwNyIsICJuX3B1YmxpY1RyYW5zcG9ydHMiLCANCiAgICAgICAgICAgICAgICAgICAgZGlzdF9tYXRyaXggPSBTWURfUE9BX21hcGRpc3QgJT4lIG11dGF0ZShkaXN0ID0gZGlzdC8xMDAwKSkNCikgJT4lIA0KICBncm91cF9ieSh0YXJnZXQsIHNvdXJjZSkgJT4lIA0KICBzdW1tYXJpc2Uocmlza19mYWN0b3IgPSBzdW0oZ3Jhdml0eV9yYW5rKSkgJT4lIA0KICAjIHNsaWNlX21heChyaXNrX2ZhY3Rvciwgbj0xMSkgJT4lIA0KICAjIHBkZigpDQogIGxlZnRfam9pbigNCiAgICBjb25maXJtZWRfY2FzZXMgJT4lIA0KICAgICAgZmlsdGVyKG5vdGlmaWNhdGlvbl9kYXRlID49IHltZCgyMDIwMTEwMSkpICU+JSANCiAgICAgIGNvdW50KHBvc3Rjb2RlLCBuYW1lID0gInRvdGFsX2Nhc2VzIikgJT4lIA0KICAgICAgbXV0YXRlKHNvdXJjZSA9IGFzLmNoYXJhY3Rlcihwb3N0Y29kZSkpLCANCiAgICBieT0ic291cmNlIg0KICApICU+JSANCiAgbXV0YXRlKHRleHRfbGFiID0gaWZlbHNlKHRvdGFsX2Nhc2VzID49IDE1LCBzb3VyY2UsIE5BKSkgJT4lIA0KICBnZ3Bsb3QoYWVzKHg9cmlza19mYWN0b3IsIHk9dG90YWxfY2FzZXMpKSArIA0KICBnZW9tX3BvaW50KCkgKyANCiAgc3RhdF9zbW9vdGgoKSArIA0KICBnZW9tX3RleHRfcmVwZWwoYWVzKGxhYmVsPXRleHRfbGFiKSkgKw0KICBsYWJzKHN1YnRpdGxlID0gIkJhc2VkIG9uIHRvdGFsIGNhc2VzIGFmdGVyIGRhdGUgMjAyMC0xMi0wMSIpICsgDQogIGdnbChiYXNlX3NpemU9MTIpDQpgYGANCg0KIyBHcmF2aXR5IHBhcmFtZXRlcnMNCg0KYGBge3J9DQpTWURfUE9BX21hcGRpc3QgJT4lIA0KICBmaWx0ZXIodGFyZ2V0ID09ICIyMTQ1IikgJT4lIA0KICBsZWZ0X2pvaW4obl9wb2lfYnlfUE9BLCBieT1jKCJzb3VyY2UiPSJQT0FfTkFNRTE2IikpICU+JSANCiAgbGVmdF9qb2luKG5fcG9pX2J5X1BPQSAlPiUgZmlsdGVyKFBPQV9OQU1FMTYgPT0gIjIxNDUiKSwgDQogICAgICAgICAgICBzdWZmaXggPSBjKCIiLCJfdGFyZ2V0IiksIA0KICAgICAgICAgICAgYnk9YygidGFyZ2V0Ij0iUE9BX05BTUUxNiIpKSAlPiUgDQogIGxlZnRfam9pbihjb25maXJtZWRfY2FzZXMgJT4lIA0KICAgICAgICAgICAgICBmaWx0ZXIobm90aWZpY2F0aW9uX2RhdGUgPj0geW1kKDIwMjAwNzAxKSwgDQogICAgICAgICAgICAgICAgICAgICBub3RpZmljYXRpb25fZGF0ZSA8IHltZCgyMDIwMTEwMSkpICU+JSANCiAgICAgICAgICAgICAgY291bnQocG9zdGNvZGUsIG5hbWU9IlRvdGFsX2Nhc2VzIikgJT4lIA0KICAgICAgICAgICAgICBtdXRhdGUoc291cmNlID0gYXMuY2hhcmFjdGVyKHBvc3Rjb2RlKSksIGJ5PSJzb3VyY2UiKSAlPiUgDQogIG11dGF0ZSh0b3RhbF9ub3JtYWxpc2VkX21hc3Nfc291cmNlID0gDQogICAgICAgICAgIG5vcm1hbGlzZWRfbl9ob3NwaXRhbHMgKyANCiAgICAgICAgICAgbm9ybWFsaXNlZF9uX3NjaG9vbHMgKyANCiAgICAgICAgICAgbm9ybWFsaXNlZF9uX3N1cGVybWFya2V0cyArIA0KICAgICAgICAgICBub3JtYWxpc2VkX25fc2hvcHBpbmdDZW50cmVzICsgDQogICAgICAgICAgIG5vcm1hbGlzZWRfbl9wdWJsaWNUcmFuc3BvcnRzKSAlPiUgDQoNCiAgbG0obG9nKFRvdGFsX2Nhc2VzICsgMC4wMSkgfiANCiAgICAgICAjIGxvZyh0b3RhbF9ub3JtYWxpc2VkX21hc3Nfc291cmNlICsgMC4wMSkgKyANCiAgICAgICBsb2cobl9ob3NwaXRhbHMgKyAwLjAxKSArDQogICAgICAgbG9nKG5fc2Nob29scyArIDAuMDEpICsNCiAgICAgICBsb2cobl9zdXBlcm1hcmtldHMgKyAwLjAxKSArDQogICAgICAgbG9nKG5fc2hvcHBpbmdDZW50cmVzICsgMC4wMSkgKw0KICAgICAgIGxvZyhuX3B1YmxpY1RyYW5zcG9ydHMgKyAwLjAxKSArDQogICAgICAgbG9nKG5faG9zcGl0YWxzICsgMC4wMSkgKw0KICAgICAgIGxvZyhkaXN0ICsgMC4wMSksIGRhdGE9LikgJT4lIA0KICBzdW1tYXJ5KCkNCmBgYA0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg==